Written from a line-by-line source review; every example output is from a real run.
Introduction
The callbackworker plugin is an async job runner: an `Start` call makes a scheduled job from a script-level callback and an input blob, which a background thread runs in FIFO order. Meanwhile, the script can do other work and at any time query the job's state via the asyncmeta-compatible verbs (Phase, Status, JobMeta). After the job completes, the response blob can be taken with `Wait`, `Take`, or `TakeBlob`, and the async lifecycle is closed by `Cancel` and the plugin-level `Close`.
Connection to the asyncmeta vocabulary
The plugin is built fully on the asyncmeta constants. `Capabilities()` returns exactly the `asyncmeta.ProfileBlobJob()` bitmask (=3701), which signals the worker supports the complete “blob-job” profile: WaitComplete, JobMeta, PhaseText, StatusText, JobInfo, Known, BlobTake, and BlobResultMeta. `Phase()` returns the asyncmeta `PhaseQueued`/`PhaseRunning`/`PhaseCompleted` value (0/1/2), and `JobMeta(jobId, key)` knows the `JobMetaPhase`, `JobMetaStatus`, `JobMetaTimeout`, `JobMetaKnown`, `JobMetaHasBlobResult`, `JobMetaBlobResultSize` keys. This shared vocabulary makes it possible to query a callbackworker job with the same functions as another asyncmeta-compatible backend's job.
Two start styles
`Start(callback, blob, timeoutMs)` passes a script-level blob to the callback in ref-style: the callback can modify the blob bytes in place, and these become the response blob's bytes. `StartBorrowedText(callback, text, timeoutMs)` works the same way, but the input is a string — the plugin passes it to the callback as a borrowed blob buffer.
Wait styles
Two functions are available for waiting on the job's completion. `Wait(jobId, timeoutMs)` BLOCKS, and when the job completes, returns the response blob — the job is destroyed afterward (one-step sync style). `WaitComplete(jobId, timeoutMs)` also blocks but only returns a 1/0 (did it complete?), and does NOT destroy the job — afterward `Phase`/`Status`/`JobMeta` can be queried, and `Take` or `TakeBlob` collects the response blob when and how the script wants.
Loading the plugin
plugin "../plugins/print/PrintPlugin"; plugin "../plugins/async_meta/AsyncMetaPlugin"; plugin "../plugins/callback_worker/CallbackWorkerPlugin";
A typical flow — one-step Start+Wait
callback i32 Echo(ref blob $Request)
{
// you may modify the request bytes; these will be the response
blob
return(1);
}
i32 main()
{
i64 $jobId;
blob $req[3];
blob $resp[8];
$req[0] = 65;
$req[1] = 66;
$req[2] = 67;
$jobId = callbackworker.Start("Echo", $req, 5000);
$resp = callbackworker.Wait($jobId, 5000);
// $resp.Length == 3, [65,66,67]
callbackworker.Close();
return(0);
}A typical flow — two-step WaitComplete + Take
i64 $jobId;
$jobId = callbackworker.Start("Echo", $req, 5000);
// ... the script does other things ...
callbackworker.WaitComplete($jobId, 5000);
if (callbackworker.Status($jobId) == 0)
{
blob $resp[8];
$resp = callbackworker.TakeBlob($jobId);
// ... processing ...
}What to know about every function (the basics)
The background thread is single-threaded FIFO: jobs run in Start order, one at a time.
timeoutMs is the callback's run time limit, NOT the Wait wait time. -1 = infinite (without forced shutdown).
Wait DESTROYS the job; the jobId is invalid afterward. Take and TakeBlob also destroy, but only if the job has completed (Phase = Completed).
WaitComplete does NOT destroy: afterward you can still query Phase, Status, JobMeta, and use Take/TakeBlob to collect the response.
Capabilities always returns the same fixed mask (3701 = ProfileBlobJob) — it does not change during runtime.
JobMeta(jobId, JobMetaKnown) does NOT fail on an unknown jobId, but returns 0 (the Known semantics). For other keys, an unknown jobId raises a runtime error.
Phase returns 0/1/2 (Queued/Running/Completed), matching the asyncmeta constants.
Status 0 = success; non-zero = the job ran with errors. ErrorText describes more precisely what happened.
Close shuts down the entire plugin-level worker thread: pending jobs break with DOMIN_STATUS_SHUTDOWN.
An error (stopping the script) is caused by an invalid jobId, a wrong argument count or type, an out-of-range timeoutMs, and touching an already-closed plugin.
How to read the signatures
callback is the name of the script-level callback (with signature `callback i32 NAME(ref blob $X)`). request is a blob the callback may modify in place; it becomes the response blob. timeoutMs is the callback's run-time limit in ms; -1 = infinite. jobId is the positive id returned by Start*. metaKey is one of the asyncmeta.JobMeta* constants. The type after the -> arrow is the return type.
Lifecycle
The plugin-level capability query and full worker-thread shutdown.
callbackworker.Capabilities
callbackworker.Capabilities() -> int
Returns the worker's capability bitmask matching the asyncmeta constants.
This function takes no arguments.
asyncmeta.ProfileBlobJob (=3701): WaitComplete | JobMeta | PhaseText | StatusText | JobInfo | Known | BlobTake | BlobResultMeta.
printf("%d\n", callbackworker.Capabilities());
printf("%d\n", (callbackworker.Capabilities() ==
asyncmeta.ProfileBlobJob()));3701 1
For checking against another asyncmeta-compatible backend: with the Supports* helpers you can verify whether a given profile package is supported. The worker's value is FIXED — it doesn't change during runtime.
callbackworker.Close
callbackworker.Close() -> int
Shuts down the worker thread: closes pending jobs and rejects new Start requests.
This function takes no arguments.
0 (always). A subsequent Start raises a runtime error.
callbackworker.Close();
printf("Close done\n");Close done
At the end of the script, for clean resource shutdown. A currently running callback can finish, but no new job is started. If you call Start afterward, you get a runtime error.
Job submission
Scheduling async jobs: a callback and an input (blob or text) → a job running on the background thread. Both forms return immediately with the jobId.
callbackworker.Start
callbackworker.Start(callback, request, timeoutMs) -> int
Schedules an async job: the callback gets the request blob's bytes in ref-style; these become the response blob's bytes.
| Parameter | Type | Description |
|---|---|---|
| callback | string | The script-level callback name. Signature: `callback i32 NAME(ref blob $X)`. |
| request | blob | The input data passed to the callback. The callback may modify it in place; the modification is visible in the response blob. |
| timeoutMs | int | The callback's RUN-time limit in ms (NOT Wait's wait time). -1 = infinite; otherwise 0..2147483647. |
The jobId (positive i64) to pass to the other operations. A bad argument or a closed worker raises a runtime error.
blob $req[3];
$req[0] = 65;
$req[1] = 66;
$req[2] = 67;
i64 $jobId;
$jobId = callbackworker.Start("Echo", $req, 5000);
printf("%d\n", ($jobId > 0));1
For the classic “work in the background” pattern: Start returns immediately, so the script can do other things. The callback may do any logic and modify the blob content — this becomes the response blob.
callbackworker.StartBorrowedText
callbackworker.StartBorrowedText(callback, text, timeoutMs) -> int
Schedules an async job with a text input — the string is passed to the callback as a borrowed blob.
| Parameter | Type | Description |
|---|---|---|
| callback | string | The script-level callback name. |
| text | string | The text passed to the callback. The callback may modify the bytes in place (as a blob). |
| timeoutMs | int | The callback's run-time limit in ms. -1 = infinite. |
The jobId (positive i64).
i64 $jobId;
$jobId = callbackworker.StartBorrowedText("Echo", "hello", 5000);
printf("%d\n", ($jobId > 0));1
Use it when the input is already text (a command, a JSON string, a newline-separated record). The borrowed buffer requires less memory copying than an explicit blob allocation + copy.
Wait and take
Waiting for the job to complete and taking the response (response blob). Wait is one-step; WaitComplete + Take/TakeBlob is the two-step pattern.
callbackworker.Wait
callbackworker.Wait(jobId, timeoutMs) -> blob
Blocks until the job completes, then returns the response blob. The job is destroyed afterward.
| Parameter | Type | Description |
|---|---|---|
| jobId | int | The jobId from Start. |
| timeoutMs | int | Maximum wait in milliseconds; -1 = infinite. |
The response blob (the request bytes as modified by the callback). A timeout raises a DOMIN_STATUS_TIMEOUT runtime error.
blob $req[3];
blob $resp[8];
$req[0] = 65;
$req[1] = 66;
$req[2] = 67;
i64 $jobId;
$jobId = callbackworker.Start("Echo", $req, 5000);
$resp = callbackworker.Wait($jobId, 5000);
printf("%d\n", $resp.Length);3
One-step sync pattern: if the script actually wants to wait and needs the result. The jobId is INVALID after Wait — any further query raises a runtime error.
callbackworker.WaitComplete
callbackworker.WaitComplete(jobId, timeoutMs) -> int
Blocks until the job completes, but does NOT destroy the job — the status and result can be queried afterward.
| Parameter | Type | Description |
|---|---|---|
| jobId | int | The jobId. |
| timeoutMs | int | Maximum wait in ms; -1 = infinite. |
1 if the job completed; 0 if the timeout expired and the job is still running.
i64 $jobId;
$jobId = callbackworker.Start("Echo", $req, 5000);
printf("%d\n", callbackworker.WaitComplete($jobId, 5000));1
Two-step pattern: if you want to separately check Status before taking the response blob. After a 1 result, Phase, Status, JobMeta, Info are queryable, and Take/TakeBlob takes the response.
callbackworker.Take
callbackworker.Take(jobId) -> blob
Returns the response blob of an already completed (Phase=Completed) job, and destroys the job.
| Parameter | Type | Description |
|---|---|---|
| jobId | int | The jobId. |
The response blob. If the job has not completed, a runtime error. If the Status is non-OK, returns the Status as an error code.
i64 $jobId;
$jobId = callbackworker.Start("Echo", $req, 5000);
callbackworker.WaitComplete($jobId, 5000);
blob $resp[8];
$resp = callbackworker.Take($jobId);
printf("%d\n", $resp.Length);3
The second phase of the two-step pattern: the job has completed, take the result. Take is a synonym for TakeBlob — same function, two names with identical semantic contract.
callbackworker.TakeBlob
callbackworker.TakeBlob(jobId) -> blob
Returns the response blob of an already completed job, and destroys the job. Synonym for Take.
| Parameter | Type | Description |
|---|---|---|
| jobId | int | The jobId. |
The response blob.
i64 $jobId;
$jobId = callbackworker.Start("Echo", $req, 5000);
callbackworker.WaitComplete($jobId, 5000);
blob $resp[8];
$resp = callbackworker.TakeBlob($jobId);
printf("%d %d %d\n", $resp[0], $resp[1], $resp[2]);65 66 67
Both names (Take and TakeBlob) are available so the caller can pick one stylistically; behavior is identical. The “Blob” in the name is intentional: it emphasizes that a blob result is being taken.
callbackworker.Cancel
callbackworker.Cancel(jobId) -> int
Attempts to remove a queued (pending) job.
| Parameter | Type | Description |
|---|---|---|
| jobId | int | The jobId. |
1 if the job was removed from the queue; 0 if it is already running or has completed.
i64 $jobId;
$jobId = callbackworker.Start("Echo", $req, 5000);
printf("%d\n", callbackworker.Cancel($jobId));0
Only jobs not yet started (queued) can be canceled. A 0 return is normal if the job is already running — then the callback must stop itself (via timeoutMs).
State queries
The job's current state: phase (queued/running/completed) and status (success/error) with both numeric code and text; plus the optional error message.
callbackworker.Phase
callbackworker.Phase(jobId) -> int
Returns the job's phase from the asyncmeta.Phase* constants.
| Parameter | Type | Description |
|---|---|---|
| jobId | int | The jobId. |
asyncmeta.PhaseQueued (=0), PhaseRunning (=1), or PhaseCompleted (=2).
i64 $jobId;
$jobId = callbackworker.Start("Echo", $req, 5000);
callbackworker.WaitComplete($jobId, 5000);
printf("%d\n", callbackworker.Phase($jobId));2
For programmatic phase checks: compare with the asyncmeta constants. The 2 value is the precondition for Take/Wait.
callbackworker.PhaseText
callbackworker.PhaseText(jobId) -> string
Returns the phase name as text.
| Parameter | Type | Description |
|---|---|---|
| jobId | int | The jobId. |
“queued”, “running”, or “completed”.
i64 $jobId;
$jobId = callbackworker.Start("Echo", $req, 5000);
callbackworker.WaitComplete($jobId, 5000);
printf("%s\n", callbackworker.PhaseText($jobId));completed
For logging or UI display. The textual counterpart of Phase's numeric value — same info in readable form.
callbackworker.Status
callbackworker.Status(jobId) -> int
Returns the job's status: 0 = success, non-zero = error (DOMIN_STATUS_*).
| Parameter | Type | Description |
|---|---|---|
| jobId | int | The jobId. |
0 if the job ran successfully; non-zero is the error code.
i64 $jobId;
$jobId = callbackworker.Start("Echo", $req, 5000);
callbackworker.WaitComplete($jobId, 5000);
printf("%d\n", callbackworker.Status($jobId));0
After WaitComplete, check this first: if 0, go ahead with Take; if non-0, ErrorText describes the error more precisely.
callbackworker.StatusText
callbackworker.StatusText(jobId) -> string
Returns the textual counterpart of the status.
| Parameter | Type | Description |
|---|---|---|
| jobId | int | The jobId. |
“success” on a successful job, other text depending on the error type.
i64 $jobId;
$jobId = callbackworker.Start("Echo", $req, 5000);
callbackworker.WaitComplete($jobId, 5000);
printf("%s\n", callbackworker.StatusText($jobId));success
For logging or user feedback. The textual counterpart of Status.
callbackworker.State
callbackworker.State(jobId) -> int
Returns a unified state code for the job (a shorthand of phase or completion-with-error).
| Parameter | Type | Description |
|---|---|---|
| jobId | int | The jobId. |
A state code describing the job's current situation (a combination of Phase + Status).
i64 $jobId;
$jobId = callbackworker.Start("Echo", $req, 5000);
callbackworker.WaitComplete($jobId, 5000);
printf("%d\n", callbackworker.State($jobId));2
Makes the job state visible in one query; a simplified summary of Phase + Status. The exact code meaning is tied to the Phase and Status defaults.
callbackworker.ErrorText
callbackworker.ErrorText(jobId) -> string
Returns the job's error message (empty on a successful job).
| Parameter | Type | Description |
|---|---|---|
| jobId | int | The jobId. |
The error message text; empty string on a successful job.
i64 $jobId;
$jobId = callbackworker.Start("Echo", $req, 5000);
callbackworker.WaitComplete($jobId, 5000);
printf("%d\n", str.Len(callbackworker.ErrorText($jobId)));0
If Status is non-0, ErrorText gives the error cause in human-readable form. For logging and UI, it gives a human-level description.
Job metadata
Detailed job queries: is it known, what is the timeout, does it have a blob result and how big — plus a combined Info string.
callbackworker.JobKnown
callbackworker.JobKnown(jobId) -> int
Tells whether the jobId belongs to a known (still living or queryable) job.
| Parameter | Type | Description |
|---|---|---|
| jobId | int | The jobId. |
1 if known; 0 if not (e.g. already destroyed by Wait/Take).
i64 $jobId;
$jobId = callbackworker.Start("Echo", $req, 5000);
printf("%d\n", callbackworker.JobKnown($jobId));1
For defensive checks: before calling a state function, this returning 0 signals the job no longer exists. JobMeta(JobMetaKnown) does the same in the asyncmeta-style query.
callbackworker.JobTimeout
callbackworker.JobTimeout(jobId) -> int
Returns the job's configured callback timeout in milliseconds.
| Parameter | Type | Description |
|---|---|---|
| jobId | int | The jobId. |
The timeoutMs value (the value passed at Start).
i64 $jobId;
$jobId = callbackworker.Start("Echo", $req, 5000);
printf("%d\n", callbackworker.JobTimeout($jobId));5000
For configuration checking or logging. Returns -1 if the job is set to infinite wait.
callbackworker.JobHasBlobResult
callbackworker.JobHasBlobResult(jobId) -> int
Tells whether the job has a blob result (completed and successful).
| Parameter | Type | Description |
|---|---|---|
| jobId | int | The jobId. |
1 if yes; 0 if no (not completed yet, or unsuccessful).
i64 $jobId;
$jobId = callbackworker.Start("Echo", $req, 5000);
callbackworker.WaitComplete($jobId, 5000);
printf("%d\n", callbackworker.JobHasBlobResult($jobId));1
Defensive check before calling Take/TakeBlob: if 0, Take raises a runtime error.
callbackworker.JobBlobResultSize
callbackworker.JobBlobResultSize(jobId) -> int
Returns the response blob's size in bytes (only for a completed, successful job).
| Parameter | Type | Description |
|---|---|---|
| jobId | int | The jobId. |
The blob size in bytes. If the job did not complete successfully, a runtime error.
i64 $jobId;
$jobId = callbackworker.Start("Echo", $req, 5000);
callbackworker.WaitComplete($jobId, 5000);
printf("%d\n", callbackworker.JobBlobResultSize($jobId));3
For memory pre-allocation: if you know how big the response will be, you can allocate a sufficiently large blob before Take. Use it together with JobHasBlobResult.
callbackworker.JobMeta
callbackworker.JobMeta(jobId, metaKey) -> int
Returns a specific meta field of the job by asyncmeta.JobMeta* keys.
| Parameter | Type | Description |
|---|---|---|
| jobId | int | The jobId. |
| metaKey | int | An asyncmeta.JobMeta* value (Phase=1, Status=2, Route=3, Timeout=4, Known=5, HasBlobResult=6, BlobResultSize=7). |
The value matching the field. JobMetaKnown returns 0 on an unknown jobId (NOT a runtime error); other keys raise a runtime error.
i64 $jobId;
$jobId = callbackworker.Start("Echo", $req, 5000);
printf("%d\n", callbackworker.JobMeta($jobId,
asyncmeta.JobMetaTimeout()));
printf("%d\n", callbackworker.JobMeta($jobId,
asyncmeta.JobMetaKnown()));5000 1
One uniform query on the job's state — with the exact keys from the asyncmeta vocabulary. If your code is portable across several backends, this form is the portable query.
callbackworker.Info
callbackworker.Info(jobId) -> string
Returns the job state's key=value diagnostic text in a single call.
| Parameter | Type | Description |
|---|---|---|
| jobId | int | The jobId. |
A space-separated key=value list (keys are stable).
i64 $jobId;
$jobId = callbackworker.Start("Echo", $req, 5000);
callbackworker.WaitComplete($jobId, 5000);
printf("%d\n", (str.Len(callbackworker.Info($jobId)) > 0));1
For detailed diagnostics in a single call — for logging or a developer interface. The keys are stable; easy to parse with str.* operations.
Practical notes
What the callbackworker plugin is good for
Offloading long-running work without blocking the main script thread (CPU-intensive callback, slow data processing).
Batch processing: several jobs started sequentially, the worker runs them in FIFO order.
Async result channel: the callback may modify the request blob in place, and the modification is visible in the response blob.
asyncmeta-compatible: Phase/Status/JobMeta use the shared vocabulary, so the code is portable to other backends.
Wait vs WaitComplete: which to use when?
Wait is one-step: it blocks and returns the response. Simple, but the job is DESTROYED afterward — you couldn't query the Status or other metadata beforehand. WaitComplete is two-step: it blocks and returns only 1/0. Afterward, Phase, Status, JobMeta are queryable, and Take/TakeBlob takes the response. If you want to check Status no matter what (and e.g. run different logic on error), WaitComplete is the choice. If you simply want to get the response and you know the job will succeed, Wait is simpler.
Cancel and running jobs
Cancel can only remove queued (not yet started) jobs — NOT running ones. If the callback must stop itself (e.g. an unbounded-time watching operation), the timeoutMs parameter gives the max run time: if it expires, the job closes with DOMIN_STATUS_TIMEOUT. Cancel returns 0 if the job is already running — this is not an error, just a state signal.
Memory management
Start internally COPIES the request blob — the script may freely use it afterward. The blob returned by Wait/Take/TakeBlob is owned by the script. The Wait + DestroyJob is automatic, so there's no leak. Close shuts down all pending jobs with DOMIN_STATUS_SHUTDOWN; those jobs are no longer accessible via Take.
Error handling
An invalid jobId, a wrong argument count or type, an out-of-range timeoutMs, and touching an already-closed plugin are reported by the runtime as a runtime error. A wait timeout (Wait) is DOMIN_STATUS_TIMEOUT; a Close-style shutdown is DOMIN_STATUS_SHUTDOWN. Take/TakeBlob only accept a completed (Phase=Completed) job — if not completed yet, a runtime error.
The callbackhttp HTTP listener plugin
Loopback or public HTTP server, request-driven callbacks, and route-level state control — complete function reference