Platform Event Listeners¶
This contract defines the modules → platform direction. The platform exposes listeners
for platform capabilities and never registers handlers tied to a particular AI, CRM,
mailer or other module.
For example, modules publish delivery.account.send, not ai.sendToWebSocket or another
module- or transport-specific name.
Processing model¶
External module
→ MoleculerBroker::emit(platform_event, JSON)
→ addressed MOL.EVENT.<platform-node> subject
→ Router
→ EventsHandlerList
→ EventHandlerRecord selected by pattern
→ envelope and payload validation
→ execution according to EventExecution
→ platform service or transport queue
Incoming events and outgoing platform events use separate registries. An incoming event is not automatically emitted into the public outbound bridge.
Handler registry¶
The C++ platform declares inbound listeners separately from action handlers:
enum class EventExecution {
Inline,
Async,
Serial
};
struct EventHandlerRecord {
std::string pattern;
std::size_t max_payload_size;
EventExecution execution;
std::function<int(
const rapidjson::Value& payload,
std::string& error
)> handler;
};
| Field | Meaning |
|---|---|
pattern |
Exact Moleculer event name or supported wildcard pattern |
max_payload_size |
Maximum accepted JSON payload size |
execution |
Dispatch policy |
handler |
Event validation and hand-off to a platform component |
The integer result and error string are internal. They are used for logs, metrics and tests, but are not returned to the event publisher.
Execution policies¶
| Policy | Use |
|---|---|
Inline |
Short validation, copying and enqueueing only; no blocking work |
Async |
Independent work executed by a bounded worker pool |
Serial |
Work whose ordering must be preserved for an agreed key |
The initial delivery listeners are Inline: they validate, format and enqueue the
message into an existing transport. Async and Serial are reserved extension policies
until a listener requires them.
Common delivery request¶
The first two listeners share this request schema:
{
"event_id": "0192f7d7-8bd5-7e1a-b6cb-0f1e37d1ad11",
"schema_version": 1,
"created_at": 1789080000,
"target": {
"id": 10001
},
"message": {
"type": "ai.run.delta",
"payload": {
"run_id": "run-123",
"delta": "Generated text"
}
}
}
Validation rules:
| Field | Rule |
|---|---|
event_id |
Required non-empty string, maximum 128 bytes |
schema_version |
Required integer; currently 1 |
created_at |
Required positive signed 64-bit Unix timestamp |
target.id |
Required positive integer |
message.type |
Required non-empty string, maximum 128 bytes |
message.payload |
Required JSON object |
| complete payload | Maximum 256 KiB for the initial listeners |
Modules send application data, not a pre-serialised WS or TCP frame. The platform owns the client transport format.
Client message¶
Both initial listeners format the request into the same client object:
{
"event": "module:event",
"type": "ai.run.delta",
"event_id": "0192f7d7-8bd5-7e1a-b6cb-0f1e37d1ad11",
"schema_version": 1,
"created_at": 1789080000,
"data": {
"run_id": "run-123",
"delta": "Generated text"
}
}
The transport is selected by the platform listener, not by a field supplied by the module. This allows the platform to change how a recipient connects without changing the module API.
Available listeners¶
| Event | target.id |
Current internal route | Status |
|---|---|---|---|
delivery.account.send |
Account login | Core::OnSendWs |
Implemented |
delivery.manager.send |
Manager ID | Core::OnSendTcp |
Implemented |
Error semantics¶
Events do not return errors to the publisher. The current dispatcher records validation, payload-limit and handler failures internally:
- malformed envelope;
- unsupported schema version;
- payload above the configured limit;
- formatter or handler exception.
Detection and metrics for a missing or inactive target and transport queue overflow are
required follow-up work. The current Core::OnSendWs and Core::OnSendTcp boundary does
not return those outcomes to the event handler.
Diagnostic logs should include the event pattern and error category and, where safely
available, event_id, target ID and message type. They must not include the complete
message.payload.
The current transport methods return no usable delivery outcome to the event handler. Therefore neither hand-off nor delivery to a connected client is acknowledged to the module. If a module requires confirmation, it must use an action or a separately agreed delivery-receipt protocol.