diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 293da738..39a6df03 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,11 +29,11 @@ jobs: fail-fast: false matrix: os: [ubuntu-latest] - scala: [2.12.16, 2.13.8, 3.2.1] + scala: [2.12.17, 2.13.10, 3.2.1] java: [temurin@11, temurin@17] project: [rootJVM] exclude: - - scala: 2.12.16 + - scala: 2.12.17 java: temurin@17 - scala: 3.2.1 java: temurin@17 @@ -89,30 +89,30 @@ jobs: key: ${{ runner.os }}-sbt-cache-v2-${{ hashFiles('**/*.sbt') }}-${{ hashFiles('project/build.properties') }} - name: Check that workflows are up to date - run: sbt 'project ${{ matrix.project }}' '++${{ matrix.scala }}' 'project /' githubWorkflowCheck + run: sbt githubWorkflowCheck - name: Check headers and formatting if: matrix.java == 'temurin@11' - run: sbt 'project ${{ matrix.project }}' '++${{ matrix.scala }}' headerCheckAll scalafmtCheckAll 'project /' scalafmtSbtCheck + run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' headerCheckAll scalafmtCheckAll 'project /' scalafmtSbtCheck - name: Test - run: sbt 'project ${{ matrix.project }}' '++${{ matrix.scala }}' test + run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' test - name: Check binary compatibility if: matrix.java == 'temurin@11' - run: sbt 'project ${{ matrix.project }}' '++${{ matrix.scala }}' mimaReportBinaryIssues + run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' mimaReportBinaryIssues - name: Generate API documentation if: matrix.java == 'temurin@11' - run: sbt 'project ${{ matrix.project }}' '++${{ matrix.scala }}' doc + run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' doc - name: Check scalafix lints if: matrix.java == 'temurin@11' && !startsWith(matrix.scala, '3.') - run: sbt 'project ${{ matrix.project }}' '++${{ matrix.scala }}' 'scalafixAll --check' + run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' 'scalafixAll --check' - name: Check unused compile dependencies if: matrix.java == 'temurin@11' - run: sbt 'project ${{ matrix.project }}' '++${{ matrix.scala }}' unusedCompileDependenciesTest + run: sbt 'project ${{ matrix.project }}' '++ ${{ matrix.scala }}' unusedCompileDependenciesTest - name: Make target directories if: github.event_name != 'pull_request' && (startsWith(github.ref, 'refs/tags/v') || github.ref == 'refs/heads/main') @@ -136,7 +136,7 @@ jobs: strategy: matrix: os: [ubuntu-latest] - scala: [2.13.8] + scala: [2.13.10] java: [temurin@11] runs-on: ${{ matrix.os }} steps: @@ -189,32 +189,22 @@ jobs: ~/Library/Caches/Coursier/v1 key: ${{ runner.os }}-sbt-cache-v2-${{ hashFiles('**/*.sbt') }}-${{ hashFiles('project/build.properties') }} - - name: Download target directories (2.12.16, rootJVM) + - name: Download target directories (2.12.17, rootJVM) uses: actions/download-artifact@v2 with: - name: target-${{ matrix.os }}-${{ matrix.java }}-2.12.16-rootJVM + name: target-${{ matrix.os }}-${{ matrix.java }}-2.12.17-rootJVM - - name: Inflate target directories (2.12.16, rootJVM) + - name: Inflate target directories (2.12.17, rootJVM) run: | tar xf targets.tar rm targets.tar - - name: Download target directories (2.13.8, rootJVM) + - name: Download target directories (2.13.10, rootJVM) uses: actions/download-artifact@v2 with: - name: target-${{ matrix.os }}-${{ matrix.java }}-2.13.8-rootJVM + name: target-${{ matrix.os }}-${{ matrix.java }}-2.13.10-rootJVM - - name: Inflate target directories (2.13.8, rootJVM) - run: | - tar xf targets.tar - rm targets.tar - - - name: Download target directories (2.13.8, rootJVM) - uses: actions/download-artifact@v2 - with: - name: target-${{ matrix.os }}-${{ matrix.java }}-2.13.8-rootJVM - - - name: Inflate target directories (2.13.8, rootJVM) + - name: Inflate target directories (2.13.10, rootJVM) run: | tar xf targets.tar rm targets.tar @@ -241,14 +231,14 @@ jobs: (echo "$PGP_PASSPHRASE"; echo; echo) | gpg --command-fd 0 --pinentry-mode loopback --change-passphrase $(gpg --list-secret-keys --with-colons 2> /dev/null | grep '^sec:' | cut --delimiter ':' --fields 5 | tail -n 1) - name: Publish - run: sbt '++${{ matrix.scala }}' tlRelease + run: sbt '++ ${{ matrix.scala }}' tlRelease site: name: Generate Site strategy: matrix: os: [ubuntu-latest] - scala: [2.13.8] + scala: [2.13.10] java: [temurin@11] runs-on: ${{ matrix.os }} steps: @@ -302,7 +292,7 @@ jobs: key: ${{ runner.os }}-sbt-cache-v2-${{ hashFiles('**/*.sbt') }}-${{ hashFiles('project/build.properties') }} - name: Generate site - run: sbt '++${{ matrix.scala }}' docs/tlSite + run: sbt '++ ${{ matrix.scala }}' docs/tlSite - name: Publish site if: github.event_name != 'pull_request' && github.ref == 'refs/heads/main' diff --git a/.scala-steward.conf b/.scala-steward.conf index 74bc924f..725607ef 100644 --- a/.scala-steward.conf +++ b/.scala-steward.conf @@ -4,6 +4,11 @@ updates.pin = [ ] updates.ignore = [ - # Inherit from series/0.23 - { groupId = "org.http4s", artifactId = "sbt-http4s-org" } + # Inherit from series/0.24 + { groupId = "org.http4s", artifactId = "http4s-dsl" }, + { groupId = "org.http4s", artifactId = "http4s-server" }, + { groupId = "org.http4s", artifactId = "http4s-scalafix-internal" }, + { groupId = "org.http4s", artifactId = "sbt-http4s-org" }, + { groupId = "org.scala-lang", artifactId = "scala3-library" }, + { groupId = "org.scala-sbt", artifactId = "sbt" } ] diff --git a/.scalafmt.conf b/.scalafmt.conf index 69f74809..1e85fdad 100644 --- a/.scalafmt.conf +++ b/.scalafmt.conf @@ -1,4 +1,4 @@ -version = 3.5.8 +version = 3.6.1 style = default diff --git a/README.md b/README.md index 36d57c5a..a69163de 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Runs http4s apps as Java servlets. Provides components for the [http4s-jetty][h ```scala libraryDependencies ++= Seq( - "org.http4s" %% "http4s-servlet" % http4sScalatagsV + "org.http4s" %% "http4s-servlet" % http4sServletV ) ``` diff --git a/build.sbt b/build.sbt index 4e5ee155..e2312b3f 100644 --- a/build.sbt +++ b/build.sbt @@ -10,8 +10,8 @@ ThisBuild / developers := List( // publish website from this branch ThisBuild / tlSitePublishBranch := Some("main") -val Scala213 = "2.13.8" -ThisBuild / crossScalaVersions := Seq("2.12.16", Scala213, "3.2.1") +val Scala213 = "2.13.10" +ThisBuild / crossScalaVersions := Seq("2.12.17", Scala213, "3.2.1") ThisBuild / scalaVersion := Scala213 // the default Scala // Jetty 10+, for testing, requires Java 11. @@ -22,7 +22,7 @@ lazy val root = tlCrossRootProject.aggregate(servlet, examples) val asyncHttpClientVersion = "2.12.3" val jettyVersion = "11.0.13" -val http4sVersion = "0.23.12" +val http4sVersion = "0.23.17" val munitCatsEffectVersion = "1.0.7" val servletApiVersion = "5.0.0" diff --git a/examples/src/main/scala/com/example/Bootstrap.scala b/examples/src/main/scala/com/example/Bootstrap.scala index e8c5cb61..cb8a4161 100644 --- a/examples/src/main/scala/com/example/Bootstrap.scala +++ b/examples/src/main/scala/com/example/Bootstrap.scala @@ -39,7 +39,9 @@ class Bootstrap extends ServletContextListener { @volatile private var shutdown: IO[Unit] = IO.unit override def contextInitialized(sce: ServletContextEvent): Unit = { - Dispatcher[IO].allocated + Dispatcher + .parallel[IO] + .allocated .flatMap { case (dispatcher, shutdown) => IO(this.shutdown = shutdown) *> IO(sce.getServletContext.mountRoutes("example", routes, dispatcher = dispatcher)) diff --git a/flake.lock b/flake.lock index a1831362..e3522b75 100644 --- a/flake.lock +++ b/flake.lock @@ -6,11 +6,11 @@ "nixpkgs": "nixpkgs" }, "locked": { - "lastModified": 1647507059, - "narHash": "sha256-1JyNnvQh1X7YhSyau1oNSv4WaTIIe/nUZYNffFzAO/g=", + "lastModified": 1671489820, + "narHash": "sha256-qoei5HDJ8psd1YUPD7DhbHdhLIT9L2nadscp4Qk37uk=", "owner": "numtide", "repo": "devshell", - "rev": "f1c3e65d20f14870fa51d762e9e54c816fe356ef", + "rev": "5aa3a8039c68b4bf869327446590f4cdf90bb634", "type": "github" }, "original": { @@ -19,22 +19,6 @@ "type": "github" } }, - "flake-compat": { - "flake": false, - "locked": { - "lastModified": 1641205782, - "narHash": "sha256-4jY7RCWUoZ9cKD8co0/4tFARpWB+57+r1bLLvXNJliY=", - "owner": "edolstra", - "repo": "flake-compat", - "rev": "b7547d3eed6f32d06102ead8991ec52ab0a4f1a7", - "type": "github" - }, - "original": { - "owner": "edolstra", - "repo": "flake-compat", - "type": "github" - } - }, "flake-utils": { "locked": { "lastModified": 1642700792, @@ -52,11 +36,11 @@ }, "flake-utils_2": { "locked": { - "lastModified": 1644229661, - "narHash": "sha256-1YdnJAsNy69bpcjuoKdOYQX0YxZBiCYZo4Twxerqv7k=", + "lastModified": 1667395993, + "narHash": "sha256-nuEHfE/LcWyuSWnS8t12N1wc105Qtau+/OdUAjtQ0rA=", "owner": "numtide", "repo": "flake-utils", - "rev": "3cecb5b042f7f209c56ffd8371b2711a290ec797", + "rev": "5aed5285a952e0b949eb3ba02c12fa4fcfef535f", "type": "github" }, "original": { @@ -83,11 +67,11 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1647350163, - "narHash": "sha256-OcMI+PFEHTONthXuEQNddt16Ml7qGvanL3x8QOl2Aao=", + "lastModified": 1672428209, + "narHash": "sha256-eejhqkDz2cb2vc5VeaWphJz8UXNuoNoM8/Op8eWv2tQ=", "owner": "nixos", "repo": "nixpkgs", - "rev": "3eb07eeafb52bcbf02ce800f032f18d666a9498d", + "rev": "293a28df6d7ff3dec1e61e37cc4ee6e6c0fb0847", "type": "github" }, "original": { @@ -113,16 +97,15 @@ "typelevel-nix": { "inputs": { "devshell": "devshell", - "flake-compat": "flake-compat", "flake-utils": "flake-utils_2", "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1647876418, - "narHash": "sha256-CNmzyjafmOkr0xZhHcShLAWw1TOKVv5Ettq8uSy3/lM=", + "lastModified": 1672639231, + "narHash": "sha256-n2S6kRPr7IE9BQSqK1KL9HxVNxL16I4js/GW0ZAa73w=", "owner": "typelevel", "repo": "typelevel-nix", - "rev": "1389f4541486669ded4648abf72e178f97563fd1", + "rev": "27b58dea50fcd1d185df9ea3024bb2e914dce0b4", "type": "github" }, "original": { diff --git a/project/build.properties b/project/build.properties index c8fcab54..c13a9b3a 100644 --- a/project/build.properties +++ b/project/build.properties @@ -1 +1 @@ -sbt.version=1.6.2 +sbt.version=1.8.1 diff --git a/project/plugins.sbt b/project/plugins.sbt index e9c30fa1..ab1a29f0 100644 --- a/project/plugins.sbt +++ b/project/plugins.sbt @@ -1,2 +1,2 @@ addSbtPlugin("com.earldouglas" % "xsbt-web-plugin" % "4.2.4") -addSbtPlugin("org.http4s" % "sbt-http4s-org" % "0.14.3") +addSbtPlugin("org.http4s" % "sbt-http4s-org" % "0.14.9") diff --git a/servlet/src/main/scala/org/http4s/servlet/AsyncHttp4sServlet.scala b/servlet/src/main/scala/org/http4s/servlet/AsyncHttp4sServlet.scala index b7443eab..1fbf6828 100644 --- a/servlet/src/main/scala/org/http4s/servlet/AsyncHttp4sServlet.scala +++ b/servlet/src/main/scala/org/http4s/servlet/AsyncHttp4sServlet.scala @@ -26,16 +26,17 @@ import jakarta.servlet.http.HttpServletRequest import jakarta.servlet.http.HttpServletResponse import org.http4s.server._ +import scala.annotation.nowarn import scala.concurrent.duration.Duration -class AsyncHttp4sServlet[F[_]]( - service: HttpApp[F], +class AsyncHttp4sServlet[F[_]] @deprecated("Use AsyncHttp4sServlet.builder", "0.23.17") ( + httpApp: HttpApp[F], asyncTimeout: Duration = Duration.Inf, servletIo: ServletIo[F], serviceErrorHandler: ServiceErrorHandler[F], dispatcher: Dispatcher[F], )(implicit F: Async[F]) - extends Http4sServlet[F](service, servletIo, dispatcher) { + extends Http4sServlet[F](httpApp, servletIo, dispatcher) { private val asyncTimeoutMillis = if (asyncTimeout.isFinite) asyncTimeout.toMillis else -1 // -1 == Inf @@ -131,16 +132,60 @@ class AsyncHttp4sServlet[F[_]]( } object AsyncHttp4sServlet { + + class Builder[F[_]] private[AsyncHttp4sServlet] ( + httpApp: HttpApp[F], + dispatcher: Dispatcher[F], + asyncTimeout: Option[Duration], + chunkSize: Option[Int], + ) { + private def copy( + httpApp: HttpApp[F] = httpApp, + dispatcher: Dispatcher[F] = dispatcher, + asyncTimeout: Option[Duration] = asyncTimeout, + chunkSize: Option[Int] = chunkSize, + ): Builder[F] = + new Builder[F]( + httpApp, + dispatcher, + asyncTimeout, + chunkSize, + ) {} + + @nowarn("cat=deprecation") + def build(implicit F: Async[F]): AsyncHttp4sServlet[F] = + new AsyncHttp4sServlet( + httpApp, + asyncTimeout.getOrElse(Duration.Inf), + NonBlockingServletIo(chunkSize.getOrElse(DefaultChunkSize)), + DefaultServiceErrorHandler, + dispatcher, + ) + + def withHttpApp(httpApp: HttpApp[F]): Builder[F] = + copy(httpApp = httpApp) + + def withDispatcher(dispatcher: Dispatcher[F]): Builder[F] = + copy(dispatcher = dispatcher) + + def withAsyncTimeout(asyncTimeout: Duration): Builder[F] = + copy(asyncTimeout = Some(asyncTimeout)) + + def withChunkSize(chunkSize: Int): Builder[F] = + copy(chunkSize = Some(chunkSize)) + } + + def builder[F[_]](httpApp: HttpApp[F], dispatcher: Dispatcher[F]): Builder[F] = + new Builder[F](httpApp, dispatcher, None, None) {} + + @deprecated("Use `builder`. `service` is renamed to `httpApp`.", "0.22.13") def apply[F[_]: Async]( service: HttpApp[F], asyncTimeout: Duration = Duration.Inf, dispatcher: Dispatcher[F], ): AsyncHttp4sServlet[F] = - new AsyncHttp4sServlet[F]( - service, - asyncTimeout, - NonBlockingServletIo[F](DefaultChunkSize), - DefaultServiceErrorHandler, - dispatcher, - ) + AsyncHttp4sServlet + .builder[F](service, dispatcher) + .withAsyncTimeout(asyncTimeout) + .build } diff --git a/servlet/src/main/scala/org/http4s/servlet/syntax/ServletContextSyntax.scala b/servlet/src/main/scala/org/http4s/servlet/syntax/ServletContextSyntax.scala index a4b38ef4..1c59fa8a 100644 --- a/servlet/src/main/scala/org/http4s/servlet/syntax/ServletContextSyntax.scala +++ b/servlet/src/main/scala/org/http4s/servlet/syntax/ServletContextSyntax.scala @@ -22,7 +22,6 @@ import cats.effect._ import cats.effect.std.Dispatcher import jakarta.servlet.ServletContext import jakarta.servlet.ServletRegistration -import org.http4s.server.DefaultServiceErrorHandler import org.http4s.server.defaults import org.http4s.syntax.all._ @@ -51,13 +50,10 @@ final class ServletContextOps private[syntax] (val self: ServletContext) extends dispatcher: Dispatcher[F], asyncTimeout: Duration = defaults.ResponseTimeout, ): ServletRegistration.Dynamic = { - val servlet = new AsyncHttp4sServlet( - service = service, - asyncTimeout = asyncTimeout, - servletIo = NonBlockingServletIo(DefaultChunkSize), - serviceErrorHandler = DefaultServiceErrorHandler[F], - dispatcher, - ) + val servlet = AsyncHttp4sServlet + .builder[F](service, dispatcher) + .withAsyncTimeout(asyncTimeout) + .build val reg = self.addServlet(name, servlet) reg.setLoadOnStartup(1) reg.setAsyncSupported(true) diff --git a/servlet/src/test/scala/org/http4s/servlet/AsyncHttp4sServletSuite.scala b/servlet/src/test/scala/org/http4s/servlet/AsyncHttp4sServletSuite.scala index bbbc9ee0..fbac1b63 100644 --- a/servlet/src/test/scala/org/http4s/servlet/AsyncHttp4sServletSuite.scala +++ b/servlet/src/test/scala/org/http4s/servlet/AsyncHttp4sServletSuite.scala @@ -31,7 +31,6 @@ import org.eclipse.jetty.client.api.{Response => JResponse} import org.eclipse.jetty.client.util.AsyncRequestContent import org.eclipse.jetty.client.util.BytesRequestContent import org.http4s.dsl.io._ -import org.http4s.server.DefaultServiceErrorHandler import org.http4s.syntax.all._ import java.nio.ByteBuffer @@ -58,7 +57,7 @@ class AsyncHttp4sServletSuite extends CatsEffectSuite { .orNotFound private val servletServer = - ResourceFixture[Int](Dispatcher[IO].flatMap(d => TestEclipseServer(servlet(d)))) + ResourceFixture[Int](Dispatcher.parallel[IO].flatMap(d => TestEclipseServer(servlet(d)))) private def get(client: HttpClient, serverPort: Int, path: String): IO[String] = IO.blocking( @@ -135,7 +134,8 @@ class AsyncHttp4sServletSuite extends CatsEffectSuite { servletServer.test("AsyncHttp4sServlet handle two-chunk, deferred POST") { server => // Show that we can read, be blocked, and read again val bytes = Stream.range(0, DefaultChunkSize).map(_.toByte).to(Array) - Dispatcher[IO] + Dispatcher + .parallel[IO] .use { dispatcher => clientR.use { client => for { @@ -175,7 +175,8 @@ class AsyncHttp4sServletSuite extends CatsEffectSuite { // We shouldn't block when we receive less than a chunk at a time servletServer.test("AsyncHttp4sServlet handle two itsy-bitsy deferred chunk POST") { server => - Dispatcher[IO] + Dispatcher + .parallel[IO] .use { dispatcher => clientR.use { client => for { @@ -215,7 +216,8 @@ class AsyncHttp4sServletSuite extends CatsEffectSuite { servletServer.test("AsyncHttp4sServlet should not reorder lots of itsy-bitsy chunks") { server => val body = (0 until 4096).map(_.toByte).toArray - Dispatcher[IO] + Dispatcher + .parallel[IO] .use { dispatcher => clientR.use { client => for { @@ -255,10 +257,9 @@ class AsyncHttp4sServletSuite extends CatsEffectSuite { clientR.use(get(_, server, "shifted")).assertEquals("shifted") } - private def servlet(dispatcher: Dispatcher[IO]) = new AsyncHttp4sServlet[IO]( - service = service, - servletIo = NonBlockingServletIo[IO](DefaultChunkSize), - serviceErrorHandler = DefaultServiceErrorHandler[IO], - dispatcher = dispatcher, - ) + private def servlet(dispatcher: Dispatcher[IO]) = + AsyncHttp4sServlet + .builder[IO](service, dispatcher) + .withChunkSize(DefaultChunkSize) + .build } diff --git a/servlet/src/test/scala/org/http4s/servlet/BlockingHttp4sServletSuite.scala b/servlet/src/test/scala/org/http4s/servlet/BlockingHttp4sServletSuite.scala index e8491e8d..79070f11 100644 --- a/servlet/src/test/scala/org/http4s/servlet/BlockingHttp4sServletSuite.scala +++ b/servlet/src/test/scala/org/http4s/servlet/BlockingHttp4sServletSuite.scala @@ -48,7 +48,7 @@ class BlockingHttp4sServletSuite extends CatsEffectSuite { .orNotFound private val servletServer = ResourceFixture( - Dispatcher[IO].flatMap(d => TestEclipseServer(servlet(d))) + Dispatcher.parallel[IO].flatMap(d => TestEclipseServer(servlet(d))) ) private def get(serverPort: Int, path: String): IO[String] = diff --git a/servlet/src/test/scala/org/http4s/servlet/RouterInServletSuite.scala b/servlet/src/test/scala/org/http4s/servlet/RouterInServletSuite.scala index 9b743f99..2e87cc97 100644 --- a/servlet/src/test/scala/org/http4s/servlet/RouterInServletSuite.scala +++ b/servlet/src/test/scala/org/http4s/servlet/RouterInServletSuite.scala @@ -22,7 +22,6 @@ import cats.effect.std.Dispatcher import munit.CatsEffectSuite import org.http4s.HttpRoutes import org.http4s.dsl.io._ -import org.http4s.server.DefaultServiceErrorHandler import org.http4s.server.Router import java.net.URL @@ -46,22 +45,28 @@ class RouterInServletSuite extends CatsEffectSuite { ) private val serverWithoutRouter = - ResourceFixture[Int](Dispatcher[IO].flatMap(d => mkServer(mainRoutes, dispatcher = d))) + ResourceFixture[Int](Dispatcher.parallel[IO].flatMap(d => mkServer(mainRoutes, dispatcher = d))) private val server = - ResourceFixture[Int](Dispatcher[IO].flatMap(d => mkServer(router, dispatcher = d))) + ResourceFixture[Int](Dispatcher.parallel[IO].flatMap(d => mkServer(router, dispatcher = d))) private val serverWithContextPath = ResourceFixture[Int]( - Dispatcher[IO].flatMap(d => mkServer(router, contextPath = "/context", dispatcher = d)) + Dispatcher + .parallel[IO] + .flatMap(d => mkServer(router, contextPath = "/context", dispatcher = d)) ) private val serverWithServletPath = ResourceFixture[Int]( - Dispatcher[IO].flatMap(d => mkServer(router, servletPath = "/servlet/*", dispatcher = d)) + Dispatcher + .parallel[IO] + .flatMap(d => mkServer(router, servletPath = "/servlet/*", dispatcher = d)) ) private val serverWithContextAndServletPath = ResourceFixture[Int]( - Dispatcher[IO].flatMap(d => - mkServer(router, contextPath = "/context", servletPath = "/servlet/*", dispatcher = d) - ) + Dispatcher + .parallel[IO] + .flatMap(d => + mkServer(router, contextPath = "/context", servletPath = "/servlet/*", dispatcher = d) + ) ) serverWithoutRouter.test( @@ -137,11 +142,8 @@ class RouterInServletSuite extends CatsEffectSuite { ): Resource[IO, Int] = TestEclipseServer(servlet(routes, dispatcher), contextPath, servletPath) private def servlet(routes: HttpRoutes[IO], dispatcher: Dispatcher[IO]) = - new AsyncHttp4sServlet[IO]( - service = routes.orNotFound, - servletIo = org.http4s.servlet.BlockingServletIo(4096), - serviceErrorHandler = DefaultServiceErrorHandler, - dispatcher = dispatcher, - ) + AsyncHttp4sServlet + .builder[IO](routes.orNotFound, dispatcher) + .build }