From a9b0c0e0860f528399eb0f323c78fe3334c2645b Mon Sep 17 00:00:00 2001 From: eikek Date: Mon, 6 Nov 2023 23:43:31 +0100 Subject: [PATCH] Fix http server startup Closes: #2358 --- .../docspell/common/util/ResourceUse.scala | 41 +++++++++++++++++++ .../main/scala/docspell/joex/JoexServer.scala | 18 ++++---- .../docspell/restserver/RestServer.scala | 33 +++++++-------- 3 files changed, 65 insertions(+), 27 deletions(-) create mode 100644 modules/common/src/main/scala/docspell/common/util/ResourceUse.scala diff --git a/modules/common/src/main/scala/docspell/common/util/ResourceUse.scala b/modules/common/src/main/scala/docspell/common/util/ResourceUse.scala new file mode 100644 index 00000000..3389e344 --- /dev/null +++ b/modules/common/src/main/scala/docspell/common/util/ResourceUse.scala @@ -0,0 +1,41 @@ +/* + * Copyright 2020 Eike K. & Contributors + * + * SPDX-License-Identifier: AGPL-3.0-or-later + */ + +package docspell.common.util + +import cats.effect._ +import cats.syntax.all._ +import fs2._ +import fs2.concurrent.{Signal, SignallingRef} + +object ResourceUse { + def apply[F[_]: Concurrent, A]( + resource: Resource[F, A] + ): Implicits.UseSyntax[F, A] = + new Implicits.UseSyntax(resource) + + object Implicits { + implicit final class UseSyntax[F[_]: Concurrent, A](resource: Resource[F, A]) { + + /** Evaluates `resource` endlessly or until the signal turns `true`. */ + def useUntil( + signal: Signal[F, Boolean], + returnValue: Ref[F, ExitCode] + ): F[ExitCode] = { + val server = Stream.resource(resource) + val blockUntilTrue = signal.discrete.takeWhile(_ == false).drain + val exit = fs2.Stream.eval(returnValue.get) + (server *> (blockUntilTrue ++ exit)).compile.lastOrError + } + + def useForever(implicit ev: Async[F]): F[ExitCode] = for { + termSignal <- SignallingRef.of[F, Boolean](false) + exitValue <- Ref.of(ExitCode.Success) + rc <- useUntil(termSignal, exitValue) + } yield rc + } + } +} diff --git a/modules/joex/src/main/scala/docspell/joex/JoexServer.scala b/modules/joex/src/main/scala/docspell/joex/JoexServer.scala index e527f811..64d4c9a3 100644 --- a/modules/joex/src/main/scala/docspell/joex/JoexServer.scala +++ b/modules/joex/src/main/scala/docspell/joex/JoexServer.scala @@ -14,6 +14,7 @@ import fs2.io.net.Network import docspell.backend.msg.Topics import docspell.common.Pools +import docspell.common.util.ResourceUse.Implicits._ import docspell.joex.routes._ import docspell.pubsub.naive.NaivePubSub import docspell.store.Store @@ -74,15 +75,14 @@ object JoexServer { Stream .resource(app) - .flatMap { app => - Stream.resource { - EmberServerBuilder - .default[F] - .withHost(cfg.bind.address) - .withPort(cfg.bind.port) - .withHttpApp(app.httpApp) - .build - } + .evalMap { app => + EmberServerBuilder + .default[F] + .withHost(cfg.bind.address) + .withPort(cfg.bind.port) + .withHttpApp(app.httpApp) + .build + .useUntil(app.termSig, app.exitRef) } }.drain } diff --git a/modules/restserver/src/main/scala/docspell/restserver/RestServer.scala b/modules/restserver/src/main/scala/docspell/restserver/RestServer.scala index 400d5d27..905e9919 100644 --- a/modules/restserver/src/main/scala/docspell/restserver/RestServer.scala +++ b/modules/restserver/src/main/scala/docspell/restserver/RestServer.scala @@ -58,24 +58,16 @@ object RestServer { Stream( restApp.subscriptions, restApp.eventConsume(maxConcurrent = 2), - Stream.resource { - if (cfg.serverOptions.enableHttp2) - EmberServerBuilder - .default[F] - .withHost(cfg.bind.address) - .withPort(cfg.bind.port) - .withMaxConnections(cfg.serverOptions.maxConnections) - .withHttpWebSocketApp(createHttpApp(setting, pubSub, restApp)) - .withHttp2 - .build - else - EmberServerBuilder - .default[F] - .withHost(cfg.bind.address) - .withPort(cfg.bind.port) - .withMaxConnections(cfg.serverOptions.maxConnections) - .withHttpWebSocketApp(createHttpApp(setting, pubSub, restApp)) - .build + Stream.eval { + EmberServerBuilder + .default[F] + .withHost(cfg.bind.address) + .withPort(cfg.bind.port) + .withMaxConnections(cfg.serverOptions.maxConnections) + .withHttpWebSocketApp(createHttpApp(setting, pubSub, restApp)) + .toggleHttp2(cfg.serverOptions.enableHttp2) + .build + .useForever } ) } @@ -164,4 +156,9 @@ object RestServer { ).pure[F] } } + + implicit final class EmberServerBuilderExt[F[_]](self: EmberServerBuilder[F]) { + def toggleHttp2(flag: Boolean) = + if (flag) self.withHttp2 else self.withoutHttp2 + } }