initialize method
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();
}