startup_tasks

Maintained by akumaCN.

A lightweight Dart package for coordinating startup work as ordered, dependency-aware tasks.

Use it to split app initialization into stages, run independent tasks concurrently, enforce timeouts, retry recoverable work, and collect a startup report for logs or diagnostics. The package has no Flutter dependency, so it can be used from pure Dart packages, Flutter apps, command-line tools, or app-specific adapter layers.

Features

  • Stage-based startup flow with StartupStage.
  • Dependency-aware task scheduling inside each stage.
  • Configurable per-stage concurrency.
  • Critical, retry, continue, and skip-dependent failure policies.
  • Per-task timeouts and cooperative cancellation.
  • Shared typed startup context with StartupKey<T>.
  • Structured StartupReport output.

Getting started

Add the package to your pubspec.yaml:

dependencies:
  startup_tasks: ^1.0.0

Import the public library:

import 'package:startup_tasks/startup_tasks.dart';

Usage

Define tasks by extending StartupTask, then pass them to StartupManager.

import 'package:startup_tasks/startup_tasks.dart';

const apiBaseUrlKey = StartupKey<String>('apiBaseUrl');

final class LoadConfigTask extends StartupTask {
  const LoadConfigTask();

  @override
  String get id => 'app.load_config';

  @override
  StartupStage get stage => StartupStage.prepare;

  @override
  bool get critical => true;

  @override
  Future<void> run(StartupContext context) async {
    context.write(apiBaseUrlKey, 'https://api.example.com');
  }
}

final class RegisterServicesTask extends StartupTask {
  const RegisterServicesTask();

  @override
  String get id => 'app.register_services';

  @override
  StartupStage get stage => StartupStage.business;

  @override
  List<String> get dependencies => const ['app.load_config'];

  @override
  Future<void> run(StartupContext context) async {
    final apiBaseUrl = context.require(apiBaseUrlKey);
    // 注册依赖 apiBaseUrl 的服务。
    // Register services that depend on apiBaseUrl.
    apiBaseUrl.length;
  }
}

Future<void> main() async {
  final manager = StartupManager(
    tasks: const [
      LoadConfigTask(),
      RegisterServicesTask(),
    ],
  );

  final report = await manager.run();
  print(report.formatSummary());
}

You can also run only part of the startup graph:

await manager.runUntil(StartupStage.business);
await manager.runAfter(StartupStage.business);

Failure handling

Each task can choose how failures affect the rest of startup:

@override
StartupFailurePolicy get failurePolicy => StartupFailurePolicy.retry;

@override
int get maxRetryCount => 2;

@override
Duration retryDelay(int retryCount) => Duration(milliseconds: 100 * retryCount);

By default, critical tasks fail startup and non-critical tasks record the failure while unrelated tasks continue.

License

MIT

Libraries

startup_tasks