call method

Future<void> call()

Executes all registered saga steps in order.

Execution semantics:

  1. Iterates through all steps in registration order
  2. Executes each step and logs its status
  3. On success: registers its compensation for later rollback
  4. On failure: executes all registered compensations in reverse order, then rethrows the original error

Compensation order (LIFO): If steps are S1, S2, S3 and S3 fails:

  • Execute: S1 → S2 → S3 (fails)
  • Compensate: C2 → C1 (reverse order)

Error handling:

  • Each compensation is awaited individually
  • If a compensation fails, the error is logged but doesn't prevent subsequent compensations from running
  • After all compensation attempts, the original error is rethrown

Logging:

  • Uses developer.log for structured logging
  • Start: ▶️ <step_name>
  • Success: ✓ <step_name>
  • Failure: ✗ <step_name> — compensating...
  • Compensation errors: Compensation failed: <error>

Returns: A Future that completes when all steps execute successfully, or rejects with the error from the first failing step (after compensation).

Throws: Re-throws the original error from any step after attempting to compensate all prior steps.

Implementation

Future<void> call() async {
  for (final step in _steps) {
    try {
      developer.log('▶️ ${step.name}');
      final result = await step.execute();
      // Register compensation in reverse order
      _compensations.insert(0, () => step.compensate(result));
      developer.log('✓ ${step.name}');
    } catch (e) {
      developer.log('✗ ${step.name} — compensating...');
      for (final comp in _compensations) {
        await comp().catchError(
          (Object? e) => developer.log('Compensation failed: $e'),
        );
      }

      rethrow;
    }
  }
}