start method

Future<void> start([
  1. CancellationToken? cancellationToken
])

Start the program.

  • HostLifetime.waitForStart
  • Services.getService{StartupValidator}().validate()
  • HostedLifecycleService.starting
  • HostedService.start
  • HostedLifecycleService.started
  • HostApplicationLifetime.applicationStarted

Implementation

Future<void> start([
  CancellationToken? cancellationToken,
]) async {
  _logger.starting();

  cancellationToken ??= CancellationToken.none;

  final cts = CancellationTokenSource.createLinkedTokenSource(
    [
      cancellationToken,
      _applicationLifetime.applicationStopping,
    ],
  );

  // Apply startup timeout if configured
  if (_options.startupTimeout != null) {
    cts.cancelAfter(_options.startupTimeout!);
  }

  final cancellationToken0 = cts.token;

  await _hostLifetime.waitForStart(cancellationToken0);
  cancellationToken0.throwIfCancellationRequested();

  var exceptions = <Exception>[];

  _hostedServices ??= services.getServices<HostedService>();
  _hostedLifecycleServices = getHostLifecycles(_hostedServices!);
  _hostStarting = true;

  var concurrent = _options.servicesStartConcurrently;
  var abortOnFirstException = !concurrent;

  void logAndRethrow() {
    if (exceptions.isNotEmpty) {
      if (exceptions.length == 1) {
        // Rethrow if it's a single error
        var singleException = exceptions[0];
        _logger.hostedServiceStartupFaulted(singleException);
        throw singleException;
      } else {
        var ex = AggregateException(
          message: 'One or more hosted services failed to start.',
          innerExceptions: exceptions,
        );
        _logger.hostedServiceStartupFaulted(ex);
        throw ex;
      }
    }
  }

  var validator = services.getService<StartupValidator>();
  if (validator != null) {
    try {
      validator.validate();
    } on Exception catch (ex) {
      exceptions.add(ex);

      // Validation errors cause startup to be aborted.
      logAndRethrow();
    }
  }

  // Call starting().
  if (_hostedLifecycleServices != null) {
    await foreachService<HostedLifecycleService>(
      _hostedLifecycleServices!,
      cancellationToken,
      concurrent,
      abortOnFirstException,
      exceptions,
      (service, token) => service.starting(token),
    );

    // Exceptions in starting cause startup to be aborted.
    logAndRethrow();
  }

  // Call start().
  await foreachService<HostedService>(
    _hostedServices!,
    cancellationToken,
    concurrent,
    abortOnFirstException,
    exceptions,
    (service, token) async {
      await service.start(token);

      if (service is BackgroundService) {
        await _tryExecuteBackgroundService(service);
      }
    },
  );

  // Exceptions in start cause startup to be aborted
  logAndRethrow();

  // Call started
  if (_hostedLifecycleServices != null) {
    await foreachService<HostedLifecycleService>(
      _hostedLifecycleServices!,
      cancellationToken,
      concurrent,
      abortOnFirstException,
      exceptions,
      (service, token) => service.started(token),
    );
  }

  // Fire HostApplicationLifetime.started
  // This catches all exceptions and does not re-throw.
  _applicationLifetime.notifyStarted();
  _logger.started();
}