50 lines
1.8 KiB
Markdown
50 lines
1.8 KiB
Markdown
# async-task
|
|
|
|
The long-running-task pattern. Plugin handlers should never do heavy
|
|
work inline — the sandbox has a fuel ceiling and the hook fan-out is
|
|
held while the handler runs. This example records an audit event
|
|
representing the work-request and returns immediately; a host-side
|
|
worker consumes the event and runs the actual work outside the
|
|
sandbox.
|
|
|
|
## Why not just block in the handler
|
|
|
|
- Sandbox fuel ceiling: handlers that exceed the budget trap and the
|
|
invocation is logged as a failure.
|
|
- Hook fan-out: each plugin subscriber serialises the host event loop.
|
|
A slow plugin slows every later subscriber.
|
|
- Audit clarity: a fast "work-requested" row in the trail is more
|
|
useful than a 30-second-blocking row that may or may not have
|
|
completed by the time the page loads.
|
|
|
|
## Pattern
|
|
|
|
```
|
|
Host emits entity.updated
|
|
│
|
|
▼
|
|
Plugin handler runs in sandbox
|
|
│
|
|
├── ctx.audit.record({ action: "async-task.work-requested", ... })
|
|
│ (writes one PluginCapabilityUse audit row + an audit event)
|
|
│
|
|
└── returns { enqueued: true } immediately
|
|
│
|
|
▼
|
|
Outbox dispatcher reads audit event
|
|
│
|
|
▼
|
|
worker subscribes to action="async-task.work-requested",
|
|
runs the long work outside the sandbox, emits a new hook
|
|
event on completion if a follow-up is needed.
|
|
```
|
|
|
|
## Caveats
|
|
|
|
- The audit body is not a payload queue — it has a small size cap and
|
|
the runtime sanitises it. Pass IDs through it, fetch the full record
|
|
from the worker side via `db.read` if needed.
|
|
- The audit row arrives *eventually* (transactional outbox), not
|
|
synchronously. If you need synchronous behaviour, plugins are the
|
|
wrong tool — call out to a regular host RPC instead.
|