Introduction
The bus plugin is the master of the callback_* family: a generic, network-protocol-agnostic async listener that dispatches arbitrary blob-based requests to a script-level callback on a background thread. The plugin supports the full asyncmeta vocabulary (Capabilities = 4095 = ProfileRouteService — every bit), and introduces the three-layer model: subscription (the callback registration), route (= subscription, the asyncmeta-vocabulary name), and job (a concrete request). The callback signature is `callback i32 NAME(ref blob $Request)`; the callback may modify the request blob in place, and that becomes the response.
The three-layer model
Subscription: the channel created by `Open(callback, timeoutMs)` — a script-callback registration with a timeout. Multiple subscriptions may live simultaneously, each with a different callback. Route: same as the subscription, just the asyncmeta-vocabulary name. The `RouteState`, `RouteCallback`, `RouteTimeout`, `RouteKnown`, `RouteMeta`, `RouteInfo`, `RoutePending`, `RouteQueued`, `RouteRunning`, `RouteDrained`, `WaitRouteDrained`, `RouteCloseAccepted`, `RouteClosedQueued`, `RouteCloseInfo`, `RouteClose` all operate on the subscription under another name — pick the code style you prefer (Subscription* is the direct form, Route* is the asyncmeta-compatible form). Job: a request scheduled by `Send`/`SendTo`/`SendBorrowedText`/`SendBorrowedTextTo`. Every job belongs to exactly one subscription (queryable via `JobSubscription` / `JobRoute`).
Send vs SendTo
`Send(request)` and `SendBorrowedText(text)` only work when EXACTLY ONE subscription is open — otherwise they fail with “bus.Send requires exactly one open subscription”. With multiple subscriptions, `SendTo(subscriptionId, request)` and `SendBorrowedTextTo(subscriptionId, text)` are the explicit forms. `Send` is a legacy convenience for the single-subscription case.
Send vs SendBorrowedText
`Send` takes a blob (the request's binary data); `SendBorrowedText` takes a string passed to the callback as a borrowed blob — fewer memory copies than building an explicit blob. The two forms are semantically equivalent: the callback always gets a ref blob parameter, and the modified bytes become the response.
Two wait styles
The plugin offers two wait functions. `WaitComplete(jobId, timeoutMs)` waits for one SPECIFIC job to finish, returning 1/0 (did it complete in time). `WaitDrained(subscriptionId, timeoutMs)` and `WaitRouteDrained(subscriptionId, timeoutMs)` wait for a SUBSCRIPTION to fully drain (every job belonging to it to finish).
Taking job results
A completed job's response blob is collected by `Take(jobId)` or `TakeBlob(jobId)` — these are synonyms. `Take/TakeBlob` destroys the job; the jobId is invalid afterward. `JobHasBlobResult(jobId)` and `JobBlobResultSize(jobId)` allow defensive pre-checks: if Status is non-zero or the job is not finished, Take raises a runtime error.
Two-step shutdown
Clean shutdown of a single subscription: (1) `RouteClose(subscriptionId)` or `CloseSubscription(subscriptionId)` — same handler; the return value is the count of queued jobs canceled by the close (0 = clean close with nothing pending). (2) `WaitRouteDrained(subscriptionId, timeoutMs)` — wait for the in-flight callbacks to finish. (3) Plugin-wide shutdown: `Close()` — closes every still-open subscription and stops the background thread. Observation: `RouteCloseAccepted` is a LATCH — once it's 1 it does not reset when reopening.
Loading the plugin
plugin "builtin:print"; plugin "../plugins/async_meta/AsyncMetaPlugin"; plugin "../plugins/bus/BusPlugin";
A typical flow — one subscription, Send + WaitComplete + Take
callback i32 Echo(ref blob $Request) { // the callback may modify the request bytes in place; // those become the response blob bytes return(1); } i32 main() { i64 $sub; i64 $jobId; blob $req[3]; blob $resp[8]; $req[0] = 65; $req[1] = 66; $req[2] = 67; $sub = bus.Open("Echo", 5000); $jobId = bus.Send($req); bus.WaitComplete($jobId, 5000); $resp = bus.TakeBlob($jobId); bus.Close(); return(0); }
What to know about every function (the basics)
Capabilities is always ProfileRouteService = 4095 = every bit (full asyncmeta profile).
Subscription/Route equivalence: same thing, two names. `JobSubscription == JobRoute`, `SubscriptionPending == RoutePending`, etc.
Send / SendBorrowedText only work with ONE open subscription; with several subs, SendTo / SendBorrowedTextTo is required.
WaitComplete waits on a JOB (jobId), NOT a subscription — the parameter name in the registration is misleading.
WaitDrained and WaitRouteDrained wait on a SUBSCRIPTION (subscriptionId): completion of every job belonging to it.
Take and TakeBlob are synonyms with identical behavior, and both destroy the job.
RouteClose and CloseSubscription are the same handler — two names, same behavior. The return is the count of canceled queued jobs.
Cancel takes a jobId and only removes jobs that have not yet started.
OpenCount is the plugin-wide, global open-subscription count.
An error (stopping the script) is caused by a wrong argument count or type, an out-of-range timeoutMs, an invalid jobId/subscriptionId, an already-closed subscription, and touching an already-closed plugin.
How to read the signatures
callback is the script-level callback name (`callback i32 NAME(ref blob $X)`). timeoutMs is the callback's run-time limit in ms; -1 = infinite. subscriptionId is the positive id given by Open. jobId is the positive id given by Send*. metaKey is one of the asyncmeta.RouteMeta* or JobMeta* values. The type after the -> arrow is the return type.
Lifecycle
Plugin capability query, opening a subscription, and plugin-wide shutdown.
bus.Capabilities
bus.Capabilities() -> intReturns the plugin's capability bitmask matching the asyncmeta constants.
This function takes no arguments.
asyncmeta.ProfileRouteService (=4095): every asyncmeta bit (the entire vocabulary supported).
printf("%d\n", bus.Capabilities()); printf("%d\n", (bus.Capabilities() == asyncmeta.ProfileRouteService()));
4095 1
For checking against another asyncmeta-compatible backend. bus supports the FULL vocabulary — the Supports* helpers return 1 for everything.
bus.Open
bus.Open(callback, timeoutMs) -> int
Opens a subscription (callback registration) and returns the subscriptionId.
| Parameter | Type | Description |
|---|---|---|
| callback | string | Script-level callback name to call. Signature: `callback i32 NAME(ref blob $X)`. |
| timeoutMs | int | Callback run-time limit in ms. -1 = infinite; otherwise 0..2147483647. |
The subscriptionId (positive i64) to pass to other operations. Bad arguments or a closed plugin raises a runtime error.
callback i32 Echo(ref blob $X) { return(1); } i64 $sub; $sub = bus.Open("Echo", 5000); printf("%d\n", ($sub > 0));
1
Create an async callback channel. You can open multiple subscriptions — one with an echo callback, another with a transform callback; SendTo targets the right channel.
bus.OpenCount
bus.OpenCount() -> intReturns the count of currently open subscriptions (plugin-wide, global view).
This function takes no arguments.
The number of open subscriptions (0 if none).
printf("%d\n", bus.OpenCount()); i64 $sub; $sub = bus.Open("Echo", 5000); printf("%d\n", bus.OpenCount());
0 1
For resource control and diagnostics. If it does not return to 0 after Close calls, that signals a resource leak.
bus.Close
bus.Close() -> intPlugin-wide shutdown: close every subscription and stop the background thread.
This function takes no arguments.
0 (always).
bus.Close(); print.Line("Close done");
Close done
At the script's end, for clean resource shutdown. A currently running callback may finish, but no new job will start.
Job submission
Schedule async jobs to an open subscription. All four verbs return immediately with the jobId.
bus.Send
bus.Send(request) -> intSchedules an async job on the single open subscription (legacy: fails with multiple subs).
| Parameter | Type | Description |
|---|---|---|
| request | blob | The input blob passed to the callback. The callback may modify it in place; the modification is visible in the response blob. |
The jobId (positive i64). Multiple subs or no open sub raises a runtime error.
i64 $sub; i64 $jobId; blob $req[3]; $req[0] = 65; $req[1] = 66; $req[2] = 67; $sub = bus.Open("Echo", 5000); $jobId = bus.Send($req); printf("%d\n", ($jobId > 0));
1
Simple, single-subscription scenarios: more convenient than SendTo since no explicit subscriptionId is needed. Use SendTo with multiple subs.
bus.SendTo
bus.SendTo(subscriptionId, request) -> intSchedules an async job to a SPECIFIC subscription.
| Parameter | Type | Description |
|---|---|---|
| subscriptionId | int | The target subscription id. |
| request | blob | The input blob passed to the callback. |
The jobId (positive i64). An invalid subscriptionId or closed subscription raises a runtime error.
i64 $sub; i64 $jobId; blob $req[3]; $req[0] = 65; $req[1] = 66; $req[2] = 67; $sub = bus.Open("Echo", 5000); $jobId = bus.SendTo($sub, $req); printf("%d\n", ($jobId > 0));
1
With multiple subscriptions (different callbacks): SendTo targets the right channel. You can build a router-style pattern — different processing callback per subscription, code dispatches to the right one.
bus.SendBorrowedText
bus.SendBorrowedText(text) -> intSchedules an async job with text input to the single open subscription.
| Parameter | Type | Description |
|---|---|---|
| text | string | The text passed to the callback (as a borrowed blob). |
The jobId (positive i64). Multiple subs or no open sub raises a runtime error.
i64 $sub; i64 $jobId; $sub = bus.Open("Echo", 5000); $jobId = bus.SendBorrowedText("hi"); printf("%d\n", ($jobId > 0));
1
For text inputs (commands, JSON strings): fewer memory copies than explicit blob construction.
bus.SendBorrowedTextTo
bus.SendBorrowedTextTo(subscriptionId, text) ->
intSchedules an async job with text input to a SPECIFIC subscription.
| Parameter | Type | Description |
|---|---|---|
| subscriptionId | int | The target subscription id. |
| text | string | The text passed to the callback. |
The jobId (positive i64).
i64 $sub; i64 $jobId; $sub = bus.Open("Echo", 5000); $jobId = bus.SendBorrowedTextTo($sub, "world"); printf("%d\n", ($jobId > 0));
1
For multiple subscriptions + text input. The borrowed-text minimizes memory allocation.
Wait and take
Wait for the job to finish, take the response blob, and cancel queued jobs.
bus.WaitComplete
bus.WaitComplete(jobId, timeoutMs) -> intBlocks until the job completes (jobId!), but does NOT destroy the job — status and result remain queryable.
| Parameter | Type | Description |
|---|---|---|
| jobId | int | The JOB id (NOT subscriptionId — the registration parameter table is misleading). |
| timeoutMs | int | Maximum wait in milliseconds; -1 = infinite. |
1 if the job completed; 0 if the timeout expired and the job is still running.
i64 $sub; i64 $jobId; blob $req[3]; $req[0] = 65; $req[1] = 66; $req[2] = 67; $sub = bus.Open("Echo", 5000); $jobId = bus.Send($req); printf("%d\n", bus.WaitComplete($jobId, 5000));
1
First step of the two-step pattern: wait for completion, then verify success via Status / JobMeta, finally Take/TakeBlob the response. IMPORTANT: the parameter name in the registration is subscriptionId, but the source treats it as `JobId` — pass the JOB id.
bus.Take
bus.Take(jobId) -> blob
Returns the response blob of an already-completed job and destroys the job. Synonym for TakeBlob.
| Parameter | Type | Description |
|---|---|---|
| jobId | int | The jobId. |
The response blob (the callback-modified request bytes). If the job has not completed, a runtime error.
i64 $sub; i64 $jobId; blob $req[3]; blob $resp[8]; $req[0] = 65; $req[1] = 66; $req[2] = 67; $sub = bus.Open("Echo", 5000); $jobId = bus.Send($req); bus.WaitComplete($jobId, 5000); $resp = bus.Take($jobId); printf("%d\n", $resp.Length);
3
Stylistic choice when the result is conceptually “taken” rather than emphasizing the blob type. Behavior is identical to TakeBlob — same handler.
bus.TakeBlob
bus.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 $sub; i64 $jobId; blob $req[3]; blob $resp[8]; $req[0] = 65; $req[1] = 66; $req[2] = 67; $sub = bus.Open("Echo", 5000); $jobId = bus.Send($req); bus.WaitComplete($jobId, 5000); $resp = bus.TakeBlob($jobId); printf("%d %d %d\n", $resp[0], $resp[1], $resp[2]);
65 66 67
Emphasizes the taken result is a blob. Identical semantics to Take — the choice is stylistic.
bus.Cancel
bus.Cancel(jobId) -> intAttempts to remove a queued (not yet started) 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 $sub; i64 $jobId; blob $req[3]; $sub = bus.Open("Echo", 5000); $jobId = bus.Send($req); printf("%d\n", bus.Cancel($jobId));
0
Only queued jobs can be canceled — running ones must self-terminate via callback timeoutMs. The 0 return is normal if the job has already started.
Subscription-level state
Current state of a subscription: open/closed, callback name, timeout, meta fields. The Subscription*/Route* names are synonyms — they query the same subscription.
bus.SubscriptionState
bus.SubscriptionState(subscriptionId) -> intReturns the subscription's state (open/closed).
| Parameter | Type | Description |
|---|---|---|
| subscriptionId | int | The subscription id. |
1 (open, asyncmeta.RouteStateOpen), 0 (closed, RouteStateClosed).
i64 $sub; $sub = bus.Open("Echo", 5000); printf("%d\n", bus.SubscriptionState($sub));
1
For programmatic state checking. Synonym of RouteState — same return under a different name.
bus.RouteState
bus.RouteState(subscriptionId) -> intSynonym of SubscriptionState: returns the subscription state under the asyncmeta vocabulary.
| Parameter | Type | Description |
|---|---|---|
| subscriptionId | int | The subscription id. |
asyncmeta.RouteStateOpen (=1) or RouteStateClosed (=0).
i64 $sub; $sub = bus.Open("Echo", 5000); printf("%d\n", bus.RouteState($sub));
1
If your code shares other asyncmeta-compatible backends, use this for consistency.
bus.SubscriptionStateText
bus.SubscriptionStateText(subscriptionId) -> string
Human-readable text of the state.
| Parameter | Type | Description |
|---|---|---|
| subscriptionId | int | The subscription id. |
“open” or “closed”.
i64 $sub; $sub = bus.Open("Echo", 5000); print.Line(bus.SubscriptionStateText($sub));
open
For logging or UI display.
bus.RouteStateText
bus.RouteStateText(subscriptionId) -> string
Synonym of SubscriptionStateText.
| Parameter | Type | Description |
|---|---|---|
| subscriptionId | int | The subscription id. |
“open” or “closed”.
i64 $sub; $sub = bus.Open("Echo", 5000); print.Line(bus.RouteStateText($sub));
open
For logging, under the asyncmeta vocabulary.
bus.SubscriptionCallback
bus.SubscriptionCallback(subscriptionId) -> string
Returns the callback name passed at Open.
| Parameter | Type | Description |
|---|---|---|
| subscriptionId | int | The subscription id. |
The callback name as text.
i64 $sub; $sub = bus.Open("Echo", 5000); print.Line(bus.SubscriptionCallback($sub));
Echo
For reflectivity and diagnostics: confirms which callback is bound to the subscription.
bus.RouteCallback
bus.RouteCallback(subscriptionId) -> string
Synonym of SubscriptionCallback.
| Parameter | Type | Description |
|---|---|---|
| subscriptionId | int | The subscription id. |
The callback name as text.
i64 $sub; $sub = bus.Open("Echo", 5000); print.Line(bus.RouteCallback($sub));
Echo
For logging, under the asyncmeta vocabulary.
bus.SubscriptionTimeout
bus.SubscriptionTimeout(subscriptionId) -> intReturns the timeout value passed at Open, in ms.
| Parameter | Type | Description |
|---|---|---|
| subscriptionId | int | The subscription id. |
The timeoutMs value; -1 for infinite.
i64 $sub; $sub = bus.Open("Echo", 5000); printf("%d\n", bus.SubscriptionTimeout($sub));
5000
Reflective query of subscription configuration.
bus.RouteTimeout
bus.RouteTimeout(subscriptionId) -> intSynonym of SubscriptionTimeout.
| Parameter | Type | Description |
|---|---|---|
| subscriptionId | int | The subscription id. |
The timeoutMs value.
i64 $sub; $sub = bus.Open("Echo", 5000); printf("%d\n", bus.RouteTimeout($sub));
5000
For logging, under the asyncmeta vocabulary.
bus.RouteKnown
bus.RouteKnown(subscriptionId) -> intTells whether the subscriptionId is known (still open in the plugin).
| Parameter | Type | Description |
|---|---|---|
| subscriptionId | int | The subscription id. |
1 if known (open); 0 if not.
i64 $sub; $sub = bus.Open("Echo", 5000); printf("%d\n", bus.RouteKnown($sub));
1
Defensive check. If 0, the subscription is already closed or unknown.
bus.RouteMeta
bus.RouteMeta(routeId, metaKey) -> intReturns a specific meta field of the subscription by asyncmeta.RouteMeta* keys.
| Parameter | Type | Description |
|---|---|---|
| routeId | int | The subscription id (the parameter name follows the asyncmeta vocabulary). |
| metaKey | int | An asyncmeta.RouteMeta* value (State, Timeout, Pending, Queued, Running, Drained, Known, CloseAccepted, ClosedQueued). |
The value for the field.
i64 $sub; $sub = bus.Open("Echo", 5000); printf("%d\n", bus.RouteMeta($sub, asyncmeta.RouteMetaState())); printf("%d\n", bus.RouteMeta($sub, asyncmeta.RouteMetaDrained()));
1 1
Uniform asyncmeta query of subscription state. For portable code across backends, this is the portable form.
bus.SubscriptionInfo
bus.SubscriptionInfo(subscriptionId) -> string
Returns the subscription state as a key=value diagnostic string.
| Parameter | Type | Description |
|---|---|---|
| subscriptionId | int | The subscription id. |
A space-separated key=value list.
i64 $sub; $sub = bus.Open("Echo", 5000); printf("%d\n", (str.Len(bus.SubscriptionInfo($sub)) > 0));
1
Detailed diagnostics in a single call.
bus.RouteInfo
bus.RouteInfo(subscriptionId) -> string
Synonym of SubscriptionInfo.
| Parameter | Type | Description |
|---|---|---|
| subscriptionId | int | The subscription id. |
A key=value diagnostic string.
i64 $sub; $sub = bus.Open("Echo", 5000); printf("%d\n", (str.Len(bus.RouteInfo($sub)) > 0));
1
Under the asyncmeta vocabulary.
Subscription-level traffic
Per-subscription job traffic metrics: pending, queued, running, drained. The Subscription*/Route* names are synonyms here as well.
bus.SubscriptionPending
bus.SubscriptionPending(subscriptionId) -> intReturns the number of pending (not yet started) jobs on the subscription.
| Parameter | Type | Description |
|---|---|---|
| subscriptionId | int | The subscription id. |
The number of pending jobs.
i64 $sub; $sub = bus.Open("Echo", 5000); printf("%d\n", bus.SubscriptionPending($sub));
0
Early signal of congestion.
bus.RoutePending
bus.RoutePending(subscriptionId) -> intSynonym of SubscriptionPending.
| Parameter | Type | Description |
|---|---|---|
| subscriptionId | int | The subscription id. |
The number of pending jobs.
i64 $sub; $sub = bus.Open("Echo", 5000); printf("%d\n", bus.RoutePending($sub));
0
For logging, under the asyncmeta vocabulary.
bus.SubscriptionQueued
bus.SubscriptionQueued(subscriptionId) -> intReturns the number of queued jobs on the subscription.
| Parameter | Type | Description |
|---|---|---|
| subscriptionId | int | The subscription id. |
The number of queued jobs.
i64 $sub; $sub = bus.Open("Echo", 5000); printf("%d\n", bus.SubscriptionQueued($sub));
0
For monitoring the internal queue length.
bus.RouteQueued
bus.RouteQueued(subscriptionId) -> intSynonym of SubscriptionQueued.
| Parameter | Type | Description |
|---|---|---|
| subscriptionId | int | The subscription id. |
The number of queued jobs.
i64 $sub; $sub = bus.Open("Echo", 5000); printf("%d\n", bus.RouteQueued($sub));
0
For logging, under the asyncmeta vocabulary.
bus.SubscriptionRunning
bus.SubscriptionRunning(subscriptionId) -> intReturns the number of currently running jobs on the subscription.
| Parameter | Type | Description |
|---|---|---|
| subscriptionId | int | The subscription id. |
The number of running jobs.
i64 $sub; $sub = bus.Open("Echo", 5000); printf("%d\n", bus.SubscriptionRunning($sub));
0
For monitoring parallelism.
bus.RouteRunning
bus.RouteRunning(subscriptionId) -> intSynonym of SubscriptionRunning.
| Parameter | Type | Description |
|---|---|---|
| subscriptionId | int | The subscription id. |
The number of running jobs.
i64 $sub; $sub = bus.Open("Echo", 5000); printf("%d\n", bus.RouteRunning($sub));
0
For logging, under the asyncmeta vocabulary.
bus.SubscriptionDrained
bus.SubscriptionDrained(subscriptionId) -> intTells whether the subscription is drained (pending = queued = running = 0).
| Parameter | Type | Description |
|---|---|---|
| subscriptionId | int | The subscription id. |
1 if drained; 0 if something is in progress.
i64 $sub; $sub = bus.Open("Echo", 5000); printf("%d\n", bus.SubscriptionDrained($sub));
1
Before clean shutdown: ensure Drained=1 before calling Close.
bus.RouteDrained
bus.RouteDrained(subscriptionId) -> intSynonym of SubscriptionDrained.
| Parameter | Type | Description |
|---|---|---|
| subscriptionId | int | The subscription id. |
1 if drained; 0 if not.
i64 $sub; $sub = bus.Open("Echo", 5000); printf("%d\n", bus.RouteDrained($sub));
1
For logging, under the asyncmeta vocabulary.
bus.WaitDrained
bus.WaitDrained(subscriptionId, timeoutMs) -> intBlocks until the subscription is drained, or timeoutMs expires.
| Parameter | Type | Description |
|---|---|---|
| subscriptionId | int | The subscription id. |
| timeoutMs | int | Maximum wait in ms; -1 = infinite. |
1 if drain occurred before timeoutMs expired; 0 if it expired.
i64 $sub; $sub = bus.Open("Echo", 5000); printf("%d\n", bus.WaitDrained($sub, 50));
1
In the two-step shutdown pattern: AFTER RouteClose, wait for full drain so every in-flight job can finish.
bus.WaitRouteDrained
bus.WaitRouteDrained(subscriptionId, timeoutMs) ->
intSynonym of WaitDrained.
| Parameter | Type | Description |
|---|---|---|
| subscriptionId | int | The subscription id. |
| timeoutMs | int | Max wait in ms. |
1 if drain occurred; 0 if expired.
i64 $sub; $sub = bus.Open("Echo", 5000); printf("%d\n", bus.WaitRouteDrained($sub, 50));
1
For logging, under the asyncmeta vocabulary.
Job-level state and metadata
Current state (phase, status, error) and metadata (timeout, owning subscription, blob result info) of a specific job. Take preconditions are checked here.
bus.State
bus.State(jobId) -> intReturns 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 (a combination of Phase + Status).
i64 $sub; i64 $jobId; blob $req[3]; $sub = bus.Open("Echo", 5000); $jobId = bus.Send($req); bus.WaitComplete($jobId, 5000); printf("%d\n", bus.State($jobId));
2
Makes the job state visible in one query; a simplified summary of Phase + Status.
bus.Phase
bus.Phase(jobId) -> intReturns the job phase from the asyncmeta.Phase* constants.
| Parameter | Type | Description |
|---|---|---|
| jobId | int | The jobId. |
asyncmeta.PhaseQueued (=0), PhaseRunning (=1), or PhaseCompleted (=2).
i64 $sub; i64 $jobId; blob $req[3]; $sub = bus.Open("Echo", 5000); $jobId = bus.Send($req); bus.WaitComplete($jobId, 5000); printf("%d\n", bus.Phase($jobId));
2
For programmatic phase checks: compare with the asyncmeta constants.
bus.PhaseText
bus.PhaseText(jobId) -> string
Returns the phase as text.
| Parameter | Type | Description |
|---|---|---|
| jobId | int | The jobId. |
“queued”, “running”, or “completed”.
i64 $sub; i64 $jobId; blob $req[3]; $sub = bus.Open("Echo", 5000); $jobId = bus.Send($req); bus.WaitComplete($jobId, 5000); print.Line(bus.PhaseText($jobId));
completed
For logging or UI display.
bus.Status
bus.Status(jobId) -> intReturns the job's status: 0 = success, non-zero = error.
| Parameter | Type | Description |
|---|---|---|
| jobId | int | The jobId. |
0 if the job ran successfully; non-zero is the error code.
i64 $sub; i64 $jobId; blob $req[3]; $sub = bus.Open("Echo", 5000); $jobId = bus.Send($req); bus.WaitComplete($jobId, 5000); printf("%d\n", bus.Status($jobId));
0
After WaitComplete, check this first: if 0, go ahead with Take; if non-0, ErrorText is more precise.
bus.StatusText
bus.StatusText(jobId) -> string
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 $sub; i64 $jobId; blob $req[3]; $sub = bus.Open("Echo", 5000); $jobId = bus.Send($req); bus.WaitComplete($jobId, 5000); print.Line(bus.StatusText($jobId));
success
For logging or user feedback.
bus.ErrorText
bus.ErrorText(jobId) -> string
Returns the job error message (empty on success).
| Parameter | Type | Description |
|---|---|---|
| jobId | int | The jobId. |
The error message text; empty string on a successful job.
i64 $sub; i64 $jobId; blob $req[3]; $sub = bus.Open("Echo", 5000); $jobId = bus.Send($req); bus.WaitComplete($jobId, 5000); printf("%d\n", str.Len(bus.ErrorText($jobId)));
0
If Status is non-0, this reveals the cause of the error.
bus.JobInfo
bus.JobInfo(jobId) -> string
Returns the job state as a key=value diagnostic string.
| Parameter | Type | Description |
|---|---|---|
| jobId | int | The jobId. |
A space-separated key=value list.
i64 $sub; i64 $jobId; blob $req[3]; $sub = bus.Open("Echo", 5000); $jobId = bus.Send($req); bus.WaitComplete($jobId, 5000); printf("%d\n", (str.Len(bus.JobInfo($jobId)) > 0));
1
Detailed job diagnostics in a single call.
bus.JobSubscription
bus.JobSubscription(jobId) -> intReturns the id of the subscription the job belongs to.
| Parameter | Type | Description |
|---|---|---|
| jobId | int | The jobId. |
The subscriptionId.
i64 $sub; i64 $jobId; blob $req[3]; $sub = bus.Open("Echo", 5000); $jobId = bus.Send($req); printf("%d\n", (bus.JobSubscription($jobId) == $sub));
1
Reflective query of the job-owner relation.
bus.JobRoute
bus.JobRoute(jobId) -> intSynonym of JobSubscription — returns the owning subscription/route id.
| Parameter | Type | Description |
|---|---|---|
| jobId | int | The jobId. |
The subscriptionId (= routeId).
i64 $sub; i64 $jobId; blob $req[3]; $sub = bus.Open("Echo", 5000); $jobId = bus.Send($req); printf("%d\n", (bus.JobRoute($jobId) == $sub));
1
Under the asyncmeta vocabulary (route = subscription).
bus.JobTimeout
bus.JobTimeout(jobId) -> intReturns the job's configured callback timeout in ms (inherited from the subscription).
| Parameter | Type | Description |
|---|---|---|
| jobId | int | The jobId. |
The timeoutMs value.
i64 $sub; i64 $jobId; blob $req[3]; $sub = bus.Open("Echo", 5000); $jobId = bus.Send($req); printf("%d\n", bus.JobTimeout($jobId));
5000
For logging or configuration checks.
bus.JobKnown
bus.JobKnown(jobId) -> intTells whether the jobId is known to the plugin.
| Parameter | Type | Description |
|---|---|---|
| jobId | int | The jobId. |
1 if known; 0 if not (e.g. already destroyed by Take).
i64 $sub; i64 $jobId; blob $req[3]; $sub = bus.Open("Echo", 5000); $jobId = bus.Send($req); printf("%d\n", bus.JobKnown($jobId));
1
Defensive check: if 0, the job no longer exists.
bus.JobMeta
bus.JobMeta(jobId, metaKey) -> intReturns 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.
i64 $sub; i64 $jobId; blob $req[3]; $sub = bus.Open("Echo", 5000); $jobId = bus.Send($req); bus.WaitComplete($jobId, 5000); printf("%d\n", bus.JobMeta($jobId, asyncmeta.JobMetaPhase()));
2
Uniform asyncmeta query on the job state — for portable code across backends.
bus.JobHasBlobResult
bus.JobHasBlobResult(jobId) -> intTells whether the job has a blob result (completed and successful).
| Parameter | Type | Description |
|---|---|---|
| jobId | int | The jobId. |
1 if yes; 0 if no.
i64 $sub; i64 $jobId; blob $req[3]; $sub = bus.Open("Echo", 5000); $jobId = bus.Send($req); bus.WaitComplete($jobId, 5000); printf("%d\n", bus.JobHasBlobResult($jobId));
1
Take precondition: if 0, Take raises a runtime error.
bus.JobBlobResultSize
bus.JobBlobResultSize(jobId) -> intReturns the response blob 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 $sub; i64 $jobId; blob $req[3]; $sub = bus.Open("Echo", 5000); $jobId = bus.Send($req); bus.WaitComplete($jobId, 5000); printf("%d\n", bus.JobBlobResultSize($jobId));
3
For memory pre-allocation: you know how big a blob to allocate for Take.
Subscription shutdown
Shutdown of a single subscription (independent of the plugin-wide Close). RouteClose and CloseSubscription are synonyms — same handler.
bus.CloseSubscription
bus.CloseSubscription(subscriptionId) -> intCloses the given subscription and cancels its queued jobs.
| Parameter | Type | Description |
|---|---|---|
| subscriptionId | int | The subscription id. |
The count of queued jobs canceled by the close (0 = clean close with nothing pending).
i64 $sub; $sub = bus.Open("Echo", 5000); printf("%d\n", bus.CloseSubscription($sub));
0
For a clean shutdown of a single subscription (without tearing down the whole plugin). The currently running callback may finish; no new job will run.
bus.RouteClose
bus.RouteClose(subscriptionId) -> intSynonym of CloseSubscription — exact same handler.
| Parameter | Type | Description |
|---|---|---|
| subscriptionId | int | The subscription id. |
The count of canceled queued jobs.
i64 $sub; $sub = bus.Open("Echo", 5000); printf("%d\n", bus.RouteClose($sub));
0
Under the asyncmeta vocabulary. Choosing between RouteClose and CloseSubscription is stylistic.
bus.RouteCloseAccepted
bus.RouteCloseAccepted(subscriptionId) -> intTells whether a close request has been accepted on the subscription.
| Parameter | Type | Description |
|---|---|---|
| subscriptionId | int | The subscription id. |
1 if yes; 0 if no RouteClose / CloseSubscription has happened yet.
i64 $sub; $sub = bus.Open("Echo", 5000); bus.RouteClose($sub); printf("%d\n", bus.RouteCloseAccepted($sub));
1
LATCH: once 1, it does not reset on reopen. Value persists for the subscription's entire life.
bus.RouteClosedQueued
bus.RouteClosedQueued(subscriptionId) -> intReturns the count of queued jobs canceled by the most recent RouteClose / CloseSubscription.
| Parameter | Type | Description |
|---|---|---|
| subscriptionId | int | The subscription id. |
The count of canceled queued jobs.
i64 $sub; $sub = bus.Open("Echo", 5000); bus.RouteClose($sub); printf("%d\n", bus.RouteClosedQueued($sub));
0
For diagnostics and logging: how many jobs were lost during shutdown.
bus.RouteCloseInfo
bus.RouteCloseInfo(subscriptionId) -> string
Returns the subscription shutdown process as a key=value diagnostic string.
| Parameter | Type | Description |
|---|---|---|
| subscriptionId | int | The subscription id. |
A space-separated key=value list.
i64 $sub; $sub = bus.Open("Echo", 5000); printf("%d\n", (str.Len(bus.RouteCloseInfo($sub)) > 0));
1
Detailed shutdown diagnostics in a single call.
Practical notes
What the bus plugin is good for
Generic async callback channel without network protocol: the code controls when and what request to send to the callback.
Parallel management of multiple channels: each subscription serves its own callback with separate state/traffic metrics.
asyncmeta compatibility with the full vocabulary: Phase, Status, JobMeta, RouteMeta, WaitDrained, RouteClose — every bit supported (Capabilities = 4095).
The subscription/route synonym pair allows stylistic choice in code — Subscription* names are direct, Route* names follow the asyncmeta convention.
Send vs SendTo usage
If your code opens only one subscription, `Send(request)` is simpler — no explicit subscriptionId needed. But if you ever open a second subscription (or some library calls Open without your knowledge), Send will fail. For defensive programming `SendTo(subscriptionId, request)` is always preferred — explicit, portable, and clearer in code about which channel you're sending to.
WaitComplete — a crucial detail
The `WaitComplete(jobId, timeoutMs)` parameter table in the registration is `gSubscriptionWaitParams` — which may suggest it takes a subscriptionId. The source code is unambiguous: `JobId = Args[0]` — it takes the JOB id. The parameter table here only encodes the argument TYPE and COUNT (one int, one int), not semantics. This is an important detail: if you accidentally pass a subscriptionId, the error message will be “job not found”. Always pass a jobId to WaitComplete.
RouteClose / CloseSubscription return value
The two calls (`RouteClose` and `CloseSubscription`) are the SAME handler — two names, identical behavior. The return value is NOT a 1/0 success flag, but the COUNT of queued jobs canceled by the close. Typically 0 (clean close with no pending jobs). A positive value: that many queued jobs were lost. A subscription closed once cannot be reopened — a second call raises a runtime error with “subscription is not open”.
Two-step shutdown pattern
(1) `RouteClose(subscriptionId)` (or `CloseSubscription`): signals the subscription is to be closed. Queued jobs are canceled; the running callback may finish. (2) `WaitRouteDrained(subscriptionId, timeoutMs)`: waits until every in-flight job is done. (3) `Close()` (plugin-wide): full plugin shutdown, including every subscription. The `RouteCloseAccepted` LATCH flips to 1 on the first RouteClose and stays — useful for diagnostics.
Error handling
An invalid jobId, subscriptionId, wrong argument count or type, out-of-range timeoutMs, touching an already-closed subscription, and touching an already-closed plugin are reported by the runtime as a runtime error, and the script stops. A WaitComplete wait-timeout is `DOMIN_STATUS_TIMEOUT`; a Close-style shutdown is `DOMIN_STATUS_SHUTDOWN`. Take/TakeBlob only accept completed (Phase=Completed) jobs.