Skip to content

Results

A result backend records each task’s TaskState and return value under its id. AsyncResult is the producer’s handle to read it. The backend is optional.

  • A request needs the answer of a short task (await r.get(timeout: ...)).
  • A client polls for a long job: return the id, then read app.resultFor(id).state.
  • You use send(dedupeKey:), chord(), or revocation that must reach workers started later; all three keep state in the backend.
  • Rose’s “fire” should create a visible pending state.
  • Pure side-effect tasks nobody reads back (emails, cache warms): omit backend: and save a Redis write per state change. AsyncResult members then throw StateError.
  • Large outputs (files, big reports): store them in object storage or your database and return a key. Results are JSON strings in Redis.
  • Business records: results expire (24 h by default on Redis). Persist anything you need to keep in your own database from inside the task.

State changes over a task’s life:

send ──▶ pending (or scheduled with an ETA)
worker ──▶ started ──▶ success | failure | retry ──▶ started ... | revoked

Each change overwrites the stored snapshot. On Redis every write resets the key’s TTL to resultTtl, so a result lives 24 hours after its last change. InMemoryResultBackend keeps results until evicted by maxEntries or hidden by ttl.

AsyncResult.get() polls the backend every pollInterval (100 ms) until a terminal state or timeout (30 s). It returns the value on success and throws TaskFailureException on failure or revoked, ResultTimeoutException on timeout. A missing key reads as pending, so a result that expired looks like a task that never ran: get then times out.

Values are stored as JSON. With Redis, a handler that returns a List<int> comes back as List<dynamic>; type the TaskRef with JSON shapes (Map<String, dynamic>, List<dynamic>) and convert on read.

Results are per id. For a workflow, the chain’s AsyncResult is its last step, a group gives a GroupResult of members, and a chord gives the callback’s result.

import 'package:gisila_queue/gisila_queue.dart';
// Start a long export and hand the id to the client.
final r = await exportCsv.delay([reportId]);
final jobId = r.id;
// Later, in another request (or another process):
final job = app.resultFor<String>(jobId);
switch (await job.state) {
case TaskState.success:
print('download: ${await job.get()}');
case TaskState.failure:
case TaskState.revoked:
print('failed');
default:
print('still working');
}