docs: add ClusterBroadcast guide for CLUSTER_EVENT and cluster/broadcast flow
Documents centralized cluster broadcasting: service -> ctx.fire("cluster/broadcast", eventJson) -> UDP CLUSTER_EVENT -> peer ctx.fire(event, data). Includes message format, service/core responsibilities, logging, networking notes, and troubleshooting.
This commit is contained in:
91
docs/ClusterBroadcast.md
Normal file
91
docs/ClusterBroadcast.md
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
## Cluster Broadcast (CLUSTER_EVENT)
|
||||||
|
|
||||||
|
### Overview
|
||||||
|
|
||||||
|
Spore supports cluster-wide event broadcasting via UDP. Services publish a local event, and the core broadcasts it to peers as a `CLUSTER_EVENT`. Peers receive the event and forward it to local subscribers through the internal event bus.
|
||||||
|
|
||||||
|
- **Local trigger**: `ctx.fire("cluster/broadcast", eventJson)`
|
||||||
|
- **UDP message**: `CLUSTER_EVENT:{json}`
|
||||||
|
- **Receiver action**: Parses `{json}` and calls `ctx.fire(event, data)`
|
||||||
|
|
||||||
|
This centralizes network broadcast in core, so services never touch UDP directly.
|
||||||
|
|
||||||
|
### Message format
|
||||||
|
|
||||||
|
- UDP payload prefix: `CLUSTER_EVENT:`
|
||||||
|
- JSON body:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"event": "<event-name>",
|
||||||
|
"data": "<json-string>" // or an inline JSON object/array
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Notes:
|
||||||
|
- The receiver accepts `data` as either a JSON string or a nested JSON object/array. Nested JSON is serialized back to a string before firing the local event.
|
||||||
|
- Keep payloads small (UDP, default buffer 512 bytes).
|
||||||
|
|
||||||
|
### Core responsibilities
|
||||||
|
|
||||||
|
- `ClusterManager` registers a centralized handler:
|
||||||
|
- Subscribes to `cluster/broadcast` to send the provided event JSON over UDP broadcast.
|
||||||
|
- Listens for incoming UDP `CLUSTER_EVENT` messages and forwards them to local subscribers via `ctx.fire(event, data)`.
|
||||||
|
- Broadcast target uses subnet-directed broadcast (e.g., `192.168.1.255`) for better reliability. Both nodes must share the same `udp_port`.
|
||||||
|
|
||||||
|
### Service responsibilities
|
||||||
|
|
||||||
|
Services send and receive events using the local event bus.
|
||||||
|
|
||||||
|
1) Subscribe to an event name and apply state from `data`:
|
||||||
|
```cpp
|
||||||
|
ctx.on("api/neopattern", [this](void* dataPtr) {
|
||||||
|
String* jsonStr = static_cast<String*>(dataPtr);
|
||||||
|
if (!jsonStr) return;
|
||||||
|
JsonDocument doc;
|
||||||
|
if (deserializeJson(doc, *jsonStr)) return;
|
||||||
|
JsonObject obj = doc.as<JsonObject>();
|
||||||
|
// Parse and apply fields from obj
|
||||||
|
});
|
||||||
|
```
|
||||||
|
|
||||||
|
2) Build a control payload and update locally via the same event:
|
||||||
|
```cpp
|
||||||
|
JsonDocument payload;
|
||||||
|
payload["pattern"] = "rainbow_cycle"; // example
|
||||||
|
payload["brightness"] = 100;
|
||||||
|
String payloadStr; serializeJson(payload, payloadStr);
|
||||||
|
ctx.fire("api/neopattern", &payloadStr);
|
||||||
|
``;
|
||||||
|
|
||||||
|
3) Broadcast to peers by delegating to core:
|
||||||
|
```cpp
|
||||||
|
JsonDocument envelope;
|
||||||
|
envelope["event"] = "api/neopattern";
|
||||||
|
envelope["data"] = payloadStr; // JSON string
|
||||||
|
String eventJson; serializeJson(envelope, eventJson);
|
||||||
|
ctx.fire("cluster/broadcast", &eventJson);
|
||||||
|
```
|
||||||
|
|
||||||
|
With this flow, services have a single codepath for applying state (the event handler). Broadcasting simply reuses the same payload.
|
||||||
|
|
||||||
|
### Logging
|
||||||
|
|
||||||
|
- Core logs source IP, payload length, and event name for received `CLUSTER_EVENT`s.
|
||||||
|
- Services can log when submitting `cluster/broadcast` and when applying control events.
|
||||||
|
|
||||||
|
### Networking considerations
|
||||||
|
|
||||||
|
- Ensure all nodes:
|
||||||
|
- Listen on the same `udp_port`.
|
||||||
|
- Are in the same subnet (for subnet-directed broadcast).
|
||||||
|
- Some networks may block global broadcast (`255.255.255.255`). Subnet-directed broadcast is used by default.
|
||||||
|
|
||||||
|
### Troubleshooting
|
||||||
|
|
||||||
|
- If peers do not react:
|
||||||
|
- Confirm logs show `CLUSTER_EVENT raw from <ip>` on the receiver.
|
||||||
|
- Verify UDP port alignment and WiFi connection/subnet.
|
||||||
|
- Check payload size (<512 bytes by default) and JSON validity.
|
||||||
|
- Ensure the service subscribed to the correct `event` name and handles `data`.
|
||||||
|
|
||||||
|
|
||||||
Reference in New Issue
Block a user