-
Notifications
You must be signed in to change notification settings - Fork 0
Messaging
Keep one hub.var(name) reference and choose the operation that fits the data. This chapter explains shared semantics; language references describe their return types, callbacks and resource settings.
| Platform | Message API |
|---|---|
| JS / Python / C++ | All operations below |
| ESP32 basic client | Exact-name events, single-response requests, asynchronous handlers and Hub drain |
| ROS | Selected operations mapped through YAML |
ESP32 scope: No business wildcards, queue groups, response collection, application Headers or subscription drain. It can call a desktop queue service and answer a desktop response collection.
In this chapter
- Choose an operation
- Names, wildcards and queues
- Requests and multiple replies
- Headers
- Limits, disconnection and shutdown
| Need | Write or send | Receive or read |
|---|---|---|
| Current state, including offline RAM updates | set(value) |
get(fallback), watchValue(handler)
|
| An event for currently connected subscribers | pub(data) |
sub(handler) |
| A request with one application response | req(data) |
handle(handler) returns the response |
| A bounded collection of responses | requestMany(data, options) |
Several handlers, or explicit replies from a subscription |
pub, sub and req are exact aliases for publish, subscribe and request. Python uses watch_value and request_many. Complete method names remain available. Queue names, timeouts and Headers are optional settings, not additional topic arguments.
| Convenience method | Behavior |
|---|---|
get(fallback) |
Reads local RAM immediately; uses the fallback only when no current value exists. It never waits for a peer or writes the fallback. |
watchValue(handler) |
Keeps the original watch timing and cancellation rules; metadata changes can still notify. |
Null, false, zero and empty strings/collections remain valid values.
This Node/browser example runs after await hub.connected():
const notice = hub.var('notice');
const subscription = await notice.sub(data => console.log(data));
await notice.pub({ text: 'hello' });
// Later: await subscription.unsubscribe();pub() does not change value, its version or pending state. sub() does not replay the current value. Repeated events are independent messages, while repeated versions of a cloud variable are deduplicated. A message-only reference still consumes reference capacity.
State methods treat the whole variable name literally. Message methods interpret dots as hierarchy separators. A concrete message name contains nonempty segments and no *, > or U+0000–U+001F/U+007F characters; its total length is 1–128 UTF-8 bytes.
| Subscription pattern | Matches | Does not match |
|---|---|---|
sensor.* |
sensor.temperature |
sensor, sensor.room.temperature
|
sensor.> |
sensor.temperature, sensor.room.temperature
|
sensor |
> |
Business messages in this namespace | Another namespace, state records or SDK reports |
- Only
subandhandleaccept patterns. Each wildcard occupies a whole segment;>must be last. - Publishing or requesting a pattern fails locally.
-
hub.var('sensor.*').set(1)writes the literal state namesensor.*; the same reference'ssub()subscribes to the message pattern. There is no implicit mode switch.
Supply the same queue to interchangeable subscribers or handlers. NATS chooses one member per group for each message; other groups and ordinary subscribers can also receive it.
Load balancing only: A queue group does not retain work, retry failed handlers or guarantee application completion. Distinct physical actuators are not interchangeable workers.
Wire subjects and permissions
| Traffic | Subject or queue |
|---|---|
| State | <hex(namespace)>.<hex(full name)> |
| Messages | _msg.v1.<hex(namespace)>.<hex(segment)>... |
| Queue group | _q.v1.<hex(namespace)>.<hex(full queue name)> |
| Reply | Native _INBOX
|
Hex is lowercase UTF-8 without normalization. Configure NATS permissions for these subjects; namespace and encoding do not grant isolation. The SDK has no raw-subject mode.
const lamp = hub.var('lamp');
const responder = await lamp.handle(async setting => {
await applyLamp(setting);
return { ok: true };
});
const result = await lamp.req({ on: true });
console.log(result.ok);applyLamp is the application's operation. The handler returns JSON; the SDK sends that value as its response.
| Omitted value | Wire value |
|---|---|
JS handler returns nothing / Python returns None
|
JSON null |
req() has no body |
JSON null |
| Request needs options but no body | Pass explicit null/None, then options |
The SDK does not guess whether an object is data or configuration.
| Request outcome | Behavior |
|---|---|
| First valid response | Return its data; default total timeout is 3 seconds |
| Detailed mode | Also return response Headers |
| Business failure | Application data, for example {ok:false,error:'unavailable'}
|
| Handler exception | Recorded locally; the caller may time out. No automatic remote error object. |
| Receiver | Receives | Reply behavior |
|---|---|---|
sub |
Matching events and requests | Return value is ignored; advanced context offers explicit reply(data, options)
|
handle |
Requests with a reply destination | One automatic reply from the return value; context can set response Headers |
Ordinary publications without a reply destination are ignored by handle.
requestMany / request_many collects response messages within a bounded window.
| Setting or result | Meaning |
|---|---|
| Default window | 3 seconds, at most 16 replies, subject to byte limits |
Detailed reason
|
deadline or maxReplies
|
| Count | Messages, not unique devices |
| Empty completed window | Valid empty result; it does not prove every device answered |
- Failures: Timeout, cancellation, disconnect and permission errors are distinct from application responses. Multi-response failures retain bounded partial results as defined by each language API.
- Invalid and late replies: A malformed first reply fails the request; a late reply never restarts it.
-
NO_RESPONDERS: The broker sees no matching subscription interest. A non-replying monitor still creates interest, so absence of this error does not prove a healthy responder.
No automatic retries. A timeout or cancellation cannot undo remote work. Retried side effects need an application operation ID and deduplication rule. A response confirms only the completion rule implemented by the handler.
Messages use native NATS Headers. JS, Python and C++ accept a string or repeated string values for each key.
| Operation | Rule |
|---|---|
| Send | Lowercase names; preserve value order within each logical key, including mixed-case input |
get |
Case-insensitive lookup of the first value |
getAll / Python get_all
|
All matching values in order |
| Enumerate | Received wire names; no cross-SDK order guarantee between different keys |
| ESP32 | Validate bounded Headers for transport status, discard application metadata; put device data in JSON |
await hub.var('notice').pub('ready', {
headers: { 'X-Trace': 'operation-42', 'X-Tag': ['device', 'status'] }
});| Content | Constraint |
|---|---|
| Header name | ASCII token |
| Header value | Visible ASCII; trim outer ASCII spaces, keep internal spaces |
| Control characters | Reject CR, LF, NUL and other controls |
| Unicode or whitespace-significant text | Put it in JSON |
| Size | Headers + payload must fit broker and SDK limits |
| Response Headers | Read through detailed request results; never inserted into the JSON body |
Messages require an active connection. New messages are rejected while disconnected or draining; the SDK does not store offline events or replay requests after reconnecting. Subscriptions are re-established on the new connection. Cloud variables retain their separate offline RAM behavior.
Subscriptions, requests, message queues, response collections and outgoing bytes are bounded.
| Condition | Result |
|---|---|
| Handler queue full | Drop new incoming messages, preserve accepted FIFO order, report SLOW_CONSUMER and counters |
| Request inbox overflow | Fail that request |
| Need backlog or drop counts | Read subscription status and hub.status().messaging for pending and in-flight work, limits and known drops |
These counters cannot prove there was no loss elsewhere in the network.
Keep callbacks short. Awaitable handlers run serially per subscription by default; ESP32 work advances through loop(). A synchronous handler that blocks its execution thread cannot be made responsive by increasing a timeout.
| Operation | Meaning |
|---|---|
pub completes |
Local bounded transport accepted the message |
flush completes |
NATS confirmed preceding transport writes, not remote execution |
unsubscribe |
Stop new delivery and discard waiting local work; admitted handlers may finish |
Subscription drain
|
Finish accepted work and replies for that subscription within a deadline |
Hub drain
|
Stop new operations, finish admitted work and requests, confirm transport and close |
close |
Immediate cleanup; it does not implicitly drain |
| Rule | Behavior |
|---|---|
| Deadline | 5 seconds for the whole operation by default |
| Expiry | Clean up SDK-controlled resources and report DRAIN_TIMEOUT
|
| Caller | Owning application, outside a managed handler |
| Node / Python | Detect handler context |
| Browser | Conservatively reject while a relevant handler is in flight, even for external calls; wait for those handlers first |
In Node/Python, owned-node cleanup may continue after DRAIN_TIMEOUT; a subsequent await hub.close() joins that cleanup. Transport interests and new operations are already stopped.
During a planned node switch, business subscriptions are retired before the replacement is activated; in-flight requests fail rather than being replayed. A handoff can lose events, and failures can leave uncertainty about remote execution. No end-to-end exactly-once guarantee is provided.
Language details: JavaScript, Python, C++, ESP32, ROS YAML.
Home · 简体中文 · Edit the docs · 文档维护
Start here: JavaScript quick start · 快速上手
- JavaScript: Start / API · 中文
- Python: Start / API · 中文
- C++: Start / API · 中文
- ESP32: Start / API · 中文
- ROS 2: Start / Config · 中文