job<T> static method
Runs body as a job: work a request handed off, run later by a queue's
worker. It runs under step — the step of the request that queued it,
which the queue keeps with the job (FlutterwareServer.step) — or, with
none, under the current zone's; and as a request of its own, so what it
writes, sends and runs gathers beneath one line of the world's trace:
job thumbnail on jobs, done in 1.2 s, 31 statements.
// Where the request queues it:
await queue.add(Job('thumbnail', file: id, step: FlutterwareServer.step));
// Where a worker runs it:
await FlutterwareServer.job('thumbnail', () => thumbnail(job.file),
step: job.step, id: job.id, queue: 'jobs');
Reports a job event as it starts and another as it ends, with how
long it took and what it threw; the error is rethrown.
body starts at once, in the caller's turn: like any async function
it runs synchronously up to its first await. Work that must come
after its caller — a webhook delivered once the request that fired it
has answered, as a webhook service would — goes in a Future:
unawaited(Future(() => FlutterwareServer.job('deliver', …))).
Implementation
static Future<T> job<T>(
String name,
FutureOr<T> Function() body, {
String? step,
Object? id,
String? queue,
}) => runZoned(() async {
var said = {'name': name, 'id': ?id?.toString(), 'queue': ?queue};
event('job', said);
var watch = Stopwatch()..start();
Object? error;
try {
return await body();
} catch (e) {
error = e;
rethrow;
} finally {
event('job', {
...said,
'ms': watch.elapsedMicroseconds / 1000,
if (error != null) 'error': '$error',
});
}
}, zoneValues: {requestIdKey: 'job-${++_jobs}', stepKey: ?step});