init method

  1. @nonVirtual
Resolvable<Unit> init({
  1. bool eagerError = true,
})
inherited

Drives the service from ServiceState.NOT_INITIALIZED to ServiceState.RUN_SUCCESS by running every listener from provideInitListeners sequentially.

Contract:

  • Calling init after dispose (any DISPOSE_* state) resolves to Err without re-running listeners. The service is terminal and cannot be re-initialized — callers must construct a fresh instance.
  • Calling init a second time while the service is still RUN_/PAUSE_/ RESUME_* resolves to Err without re-running listeners (idempotent — listeners run exactly once per service lifetime).
  • On the first valid call: listeners run; the service transitions to ServiceState.RUN_ATTEMPT during execution and then RUN_SUCCESS / RUN_ERROR depending on outcome. If eagerError is true (default), the chain short-circuits on the first listener error.

Returning Err on invalid transitions (instead of silent Ok in release or AssertionError in debug) is a mission-critical reliability choice: callers checking the awaited Result can detect "init was skipped because the service is in the wrong state" without relying on asserts being on.

Implementation

@nonVirtual
Resolvable<Unit> init({bool eagerError = true}) {
  return _sequencer.then((prev) {
    // Debug-only diagnostic: surface contract violations early so dev
    // builds catch them before they manifest as silent Errs in prod.
    assert(
      !state.didDispose(),
      '$runtimeType.init: cannot be called after dispose; state is $state. '
      'Services are terminal after dispose — construct a fresh instance.',
    );
    if (state.didDispose()) {
      return Sync<Option>.err(
        Err('init: cannot be called after dispose; '
            'state is $state.'),
      );
    }
    assert(
      state == ServiceState.NOT_INITIALIZED,
      '$runtimeType.init: already initialized; state is $state. '
      'init() runs listeners exactly once per service lifetime.',
    );
    if (state != ServiceState.NOT_INITIALIZED) {
      return Sync<Option>.err(
        Err('init: already initialized; state is $state. '
            'init() runs listeners exactly once per service lifetime.'),
      );
    }
    return _updateState(
      providerFunction: provideInitListeners,
      eagerError: eagerError,
      attemptState: ServiceState.RUN_ATTEMPT,
      successState: ServiceState.RUN_SUCCESS,
      errorState: ServiceState.RUN_ERROR,
      phaseName: 'init',
      onSuccessMustNotThrow: Some(() {
        _didEverInitAndSuccessfully = true;
      }),
    );
  }).toUnit();
}