initialize method

Future<void> initialize({
  1. required Map<String, dynamic> config,
  2. List<String> args = const [],
  3. FutureOr<void> setup()?,
})

Boots the app and starts serving.

setup runs once in every isolate that serves requests, before the config's providers boot. Put there what would otherwise sit in main() ahead of this call — registering a database driver, an auth provider — because with APP_ISOLATES above 1 each extra isolate starts from scratch and never runs main():

await Application().initialize(
  config: config,
  setup: () async {
    registerMySqlDriver();
    await AuthServiceProvider().register(...);
  },
);

It is sent to each isolate, so it must not capture anything that cannot be: an open connection or socket, say.

Implementation

Future<void> initialize({
  required Map<String, dynamic> config,
  List<String> args = const [],
  FutureOr<void> Function()? setup,
}) async {
  keepServingOnUncaughtErrors(log: !_isWorker);
  await Localization().init();

  IoCContainer().register<RequestHandler>(() => RequestHandler());
  IoCContainer().register<SessionManager>(
    () => SessionManager(),
    singleton: true,
  );

  // APP_KEY keys session encryption and the framework's HMACs, so a
  // short one weakens both. 32 characters is the minimum.
  final appKey = env('APP_KEY');
  if (appKey == null || appKey is! String || appKey.length < 32) {
    throw Exception(
      'APP_KEY missing or too short (must be at least 32 characters). '
      'Generate one with `openssl rand -base64 32` and add it to .env',
    );
  }

  // Here first, so a setup that fails stops the app before any other
  // isolate has started.
  await setup?.call();

  // Workers get the config before this isolate's providers boot, so
  // each one boots from the same untouched config.
  if (!_isWorker &&
      serverIsolateCount > 1 &&
      Platform.environment[routeDumpEnvVar] != '1') {
    await _spawnWorkers(config, args, setup);
  }

  final server = BaseHttpServer(
    config: config,
    args: args,
    isWorker: _isWorker,
  );
  _server = server;
  await server.startServer();

  if (!_isWorker) _closeOnSignals();
}