|
1 | 1 | package sttp.tapir.perf.apis
|
2 | 2 |
|
3 |
| -import cats.effect.{ExitCode, IO, IOApp} |
| 3 | +import cats.effect.{IO, Resource, ResourceApp} |
4 | 4 |
|
5 | 5 | import scala.reflect.runtime.universe
|
6 | 6 |
|
7 | 7 | trait ServerRunner {
|
8 |
| - def start: IO[ServerRunner.KillSwitch] |
| 8 | + def runServer: Resource[IO, Unit] |
9 | 9 | }
|
10 | 10 |
|
11 | 11 | /** Can be used as a Main object to run a single server using its short name. Running perfTests/runMain
|
12 | 12 | * [[sttp.tapir.perf.apis.ServerRunner]] will load special javaOptions configured in build.sbt, enabling recording JFR metrics. This is
|
13 | 13 | * useful when you want to guarantee that the server runs in a different JVM than test runner, so that memory and CPU metrics are recorded
|
14 | 14 | * only in the scope of the server JVM.
|
15 | 15 | */
|
16 |
| -object ServerRunner extends IOApp { |
17 |
| - type KillSwitch = IO[Unit] |
18 |
| - val NoopKillSwitch = IO.pure(IO.unit) |
| 16 | +object ServerRunner extends ResourceApp.Forever { |
| 17 | + |
19 | 18 | private val runtimeMirror = universe.runtimeMirror(getClass.getClassLoader)
|
| 19 | + private val requireArg: Resource[IO, Unit] = Resource.raiseError( |
| 20 | + new IllegalArgumentException(s"Unspecified server name. Use one of: ${TypeScanner.allServers}"): Throwable |
| 21 | + ) |
| 22 | + private def notInstantiated(name: ServerName)(e: Throwable): IO[ServerRunner] = IO.raiseError( |
| 23 | + new IllegalArgumentException( |
| 24 | + s"ERROR! Could not find object ${name.fullName} or it doesn't extend ServerRunner", e |
| 25 | + ) |
| 26 | + ) |
20 | 27 |
|
21 |
| - def run(args: List[String]): IO[ExitCode] = { |
22 |
| - val shortServerName = args.headOption.getOrElse { |
23 |
| - throw new IllegalArgumentException(s"Unspecified server name. Use one of: ${TypeScanner.allServers}") |
24 |
| - } |
25 |
| - for { |
26 |
| - killSwitch <- startServerByTypeName(ServerName.fromShort(shortServerName)) |
27 |
| - _ <- IO.never.guarantee(killSwitch) |
28 |
| - } yield ExitCode.Success |
29 |
| - } |
| 28 | + def run(args: List[String]): Resource[IO, Unit] = |
| 29 | + args.headOption.map(ServerName.fromShort).map(startServerByTypeName).getOrElse(requireArg) |
30 | 30 |
|
31 |
| - def startServerByTypeName(serverName: ServerName): IO[ServerRunner.KillSwitch] = { |
| 31 | + def startServerByTypeName(serverName: ServerName): Resource[IO, Unit] = |
32 | 32 | serverName match {
|
33 |
| - case ExternalServerName => NoopKillSwitch |
34 |
| - case _ => |
35 |
| - try { |
| 33 | + case ExternalServerName => Resource.unit |
| 34 | + case _ => Resource.eval( |
| 35 | + IO({ |
36 | 36 | val moduleSymbol = runtimeMirror.staticModule(serverName.fullName)
|
37 | 37 | val moduleMirror = runtimeMirror.reflectModule(moduleSymbol)
|
38 |
| - val instance: ServerRunner = moduleMirror.instance.asInstanceOf[ServerRunner] |
39 |
| - instance.start |
40 |
| - } catch { |
41 |
| - case e: Throwable => |
42 |
| - IO.raiseError( |
43 |
| - new IllegalArgumentException(s"ERROR! Could not find object ${serverName.fullName} or it doesn't extend ServerRunner", e) |
44 |
| - ) |
45 |
| - } |
| 38 | + moduleMirror.instance.asInstanceOf[ServerRunner] |
| 39 | + }).handleErrorWith(notInstantiated(serverName)) |
| 40 | + ).flatMap(_.runServer) |
46 | 41 | }
|
47 |
| - } |
48 | 42 | }
|
0 commit comments