serve function

Future<ServerHandle> serve(
  1. Router router,
  2. InternetAddress address,
  3. int port, {
  4. SecurityContext? securityContext,
  5. bool shared = false,
  6. BackgroundTasks? background,
})

Serves router, counting requests so shutdown can wait for them.

shared lets several isolates bind the same port, which is what serveIsolates uses; on its own a single server has no reason to set it.

background is drained alongside the requests. When it is omitted, a BackgroundTasks attached to router with withState is used instead — so a clustered server, whose registry is built inside each isolate, needs no extra wiring to be drained.

final server = await serve(app, InternetAddress.anyIPv4, 8080);
await ProcessSignal.sigterm.watch().first;
await server.close(drain: const Duration(seconds: 15));

Implementation

Future<ServerHandle> serve(
  Router router,
  InternetAddress address,
  int port, {
  SecurityContext? securityContext,
  bool shared = false,
  BackgroundTasks? background,
}) async {
  final inFlight = _InFlight();
  // Falling back to the router's own state means `withState(tasks)` is enough,
  // and a clustered server — where the registry is built inside each isolate and
  // cannot be handed in from outside — drains its tasks without any extra
  // wiring.
  final tasks = background ?? backgroundTasksIn(router);
  final handler = router.handler;

  final server = await shelf_io.serve(
    (request) async {
      inFlight.enter();
      try {
        return _flushIfStreamed(await handler(request));
      } finally {
        inFlight.leave();
      }
    },
    address,
    port,
    securityContext: securityContext,
    shared: shared,
  );

  return ServerHandle._(server, inFlight, tasks, disposableLayersIn(router));
}