runTask<T> method

Future<T?> runTask<T>(
  1. Future<T> task(), {
  2. String? id,
  3. TaskPriority priority = TaskPriority.normal,
  4. int retries = 0,
  5. Duration? retryDelay,
  6. bool useExponentialBackoff = true,
  7. void onError(
    1. Object error,
    2. StackTrace stackTrace
    )?,
  8. TaskCachePolicy<T>? cachePolicy,
})

Executes an asynchronous task with optional retry and priority logic.

Returns the result of the task, or throws if it fails (unless handled internally).

  • task: The async function to execute.
  • id: An optional ID for the task (useful for cancellation).
  • priority: The priority of the task relative to others in the queue.
  • retries: The number of times to retry the task upon failure.
  • retryDelay: The initial delay before the first retry.
  • useExponentialBackoff: Whether to increase the delay exponentially for subsequent retries.
  • onError: A custom error handler for this specific task. If not provided, onServiceError is used.
  • cachePolicy: If provided, the task result will be cached and reused until it expires.

Implementation

Future<T?> runTask<T>(
  Future<T> Function() task, {
  String? id,
  TaskPriority priority = TaskPriority.normal,
  int retries = 0,
  Duration? retryDelay,
  bool useExponentialBackoff = true,
  void Function(Object error, StackTrace stackTrace)? onError,
  TaskCachePolicy<T>? cachePolicy,
}) async {
  final taskId = id ?? _generateTaskId();

  if (cachePolicy != null) {
    final cacheKey = cachePolicy.key ?? taskId;
    final cachedJson = await taskCacheProvider.read(cacheKey);

    if (cachedJson != null) {
      final expiresAt =
          DateTime.fromMillisecondsSinceEpoch(cachedJson['expiresAt'] as int);
      if (DateTime.now().isBefore(expiresAt)) {
        final data = cachedJson['data'] as Map<String, dynamic>;
        try {
          return cachePolicy.fromJson(data);
        } catch (e) {
          // If deserialization fails, treat as cache miss and delete
          await taskCacheProvider.delete(cacheKey);
        }
      } else {
        // Expired
        await taskCacheProvider.delete(cacheKey);
      }
    }
  }

  final result = await _tasksEngine.schedule(
    task: task,
    id: taskId,
    priority: priority,
    retries: retries,
    retryDelay: retryDelay,
    useExponentialBackoff: useExponentialBackoff,
    onError: (e, s) {
      final handler = onError ?? onServiceError;
      if (handler != null) {
        handler.call(e, s);
      } else {
        // If no handler, we allow the engine to complete the future with an error
        // to ensure propagation.
        throw e;
      }
    },
  );

  if (cachePolicy != null && result != null) {
    final cacheKey = cachePolicy.key ?? taskId;
    await taskCacheProvider.write(cacheKey, {
      'expiresAt': DateTime.now().add(cachePolicy.ttl).millisecondsSinceEpoch,
      'data': cachePolicy.toJson(result),
    });
  }

  return result;
}