Skip to content

Commit 4437410

Browse files
committed
feat: enhance error handling and metrics in MQTT application
- Update error handling tests to ensure validation errors propagate correctly with payloads. - Introduce timeout and concurrency features in the router configuration to manage handler execution limits. - Add metrics tracking for dispatch and publish events, capturing success and error states. - Implement shared subscription parsing for MQTT 5, allowing for group and topic filter extraction. - Add publish hook context to allow mutation of publish options before sending. - Enhance TypeBox and Zod documentation to clarify usage and integration with AsyncAPI.
1 parent 0170f06 commit 4437410

45 files changed

Lines changed: 2423 additions & 1026 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,53 @@ together stay readable.
77

88
The format is loosely based on [Keep a Changelog](https://keepachangelog.com/).
99

10-
## 2026-06-22
10+
## 2026-06-22 — 0.2.1
11+
12+
`@mqttkit/core@0.2.1`
13+
14+
### Added — `@mqttkit/core` 0.2.1
15+
16+
- **MQTT 5 shared subscriptions** (`$share/<group>/<filter>`).
17+
`parseSharedSubscription()` follows §4.8.2; `canSubscribe()` strips the
18+
prefix before route matching and exposes `shared.group` to the subscribe
19+
policy. Lets you deploy multiple consumer instances behind one broker
20+
without custom load-balancing.
21+
- **Per-route `timeout` and `concurrency`**. `topic({ timeout, concurrency })`
22+
guards handler execution. Timeout surfaces as `phase: 'timeout'`; concurrency
23+
rejection surfaces as `phase: 'overload'`. Inflight count is tracked on the
24+
route for use by metrics and graceful shutdown.
25+
- **`app.onMetric(handler)`**. Emits a structured `MqttMetricEvent` once per
26+
dispatch and once per publish — `{ type, topic, route?, durationMs, result,
27+
errorPhase? }`. Designed to feed Prometheus / OpenTelemetry / statsd without
28+
middleware around every route.
29+
- **Graceful shutdown**. `app.stop({ drain: true, timeout: 30_000 })` is now
30+
the default behaviour: the dispatcher refuses new inbound dispatches, polls
31+
every route's `inflight` count to zero (or until the timeout), then runs
32+
`onStop` hooks, cancels in-flight RPC, and stops the broker adapter.
33+
`app.activeCount()` reports the current sum of in-flight handlers for health
34+
checks. Pass `{ drain: false }` for the legacy immediate shutdown.
35+
- **MQTT 5 user properties on `ctx`**. `ctx.userProperties` exposes inbound
36+
`packet.properties.userProperties` as a flat read view, so middleware can
37+
extract `traceparent`, correlation IDs, or any side-band metadata without
38+
touching adapter-specific packet shape.
39+
- **Outbound publish hooks**. `app.onBeforePublish(hook)` runs immediately
40+
before every outbound publish (both `app.publish()` and `ctx.publish()` /
41+
`ctx.reply()` / `app.request()`, which all funnel through the same path).
42+
Hooks receive a mutable `{ topic, payload, options }` view and can mutate
43+
`options` — typical use is merging `traceparent` into
44+
`options.properties.userProperties` so OTel context propagates across
45+
brokers. A throw aborts the publish and surfaces through `onError` with
46+
`phase: 'publish'`.
47+
- **Raw payload on `onError`**. `MqttErrorPayload.payload` carries the raw
48+
buffer for inbound phases (`validation` / `policy` / `middleware` / `handler` /
49+
`timeout` / `overload`) and the original `MqttPayload` for `publish`. Lets
50+
exporters (Sentry, structured logs) capture the offending message body, not
51+
just the topic.
52+
- **New docs pages** under the Production section: `Shared Subscriptions`,
53+
`Handler Timeout & Concurrency`, `Metrics`, `Graceful Shutdown`,
54+
`Tracing & User Properties` (with full OpenTelemetry wiring example).
55+
56+
## 2026-06-22 — 0.2.0
1157

1258
`@mqttkit/core@0.2.0`, `@mqttkit/aedes@0.2.0`, `@mqttkit/asyncapi@0.2.0`,
1359
`@mqttkit/typebox@0.1.0` (initial), `@mqttkit/zod@0.1.0` (initial).

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ Full documentation: **<https://mqttkit.keyp.dev>** ([简体中文](https://mqttk
1414
- `router().topic()` declares MQTT topic routes with publish / subscribe policies.
1515
- Topic params (`devices/:uid/events`), payload validation via any [Standard Schema](https://standardschema.dev/) validator, and injected services on `ctx`.
1616
- MQTT 5 RPC with `app.request()` and `ctx.reply()`.
17+
- MQTT 5 shared subscriptions (`$share/<group>/<filter>`) for multi-instance fan-out.
18+
- Per-route `timeout` and `concurrency` guards surface as `onError` phases.
19+
- `app.onMetric()` emits structured per-dispatch / per-publish events for Prometheus / OpenTelemetry.
1720
- `app.on()` observes broker lifecycle events; `app.publish()` lets workers push messages.
1821
- Adapters: `@mqttkit/aedes` (TCP + WebSocket) and `@mqttkit/asyncapi` (AsyncAPI 3.0 docs).
1922
- In-memory `TestBroker` for unit tests. Built for Bun and TypeScript.

README.zh-CN.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ mqttkit 不重新实现 MQTT 协议。CONNECT、SUBSCRIBE、PUBLISH、QoS、reta
1414
- `router().topic()` 声明 MQTT topic route 及发布 / 订阅策略。
1515
- topic 参数(`devices/:uid/events`),payload 校验支持任意 [Standard Schema](https://standardschema.dev/) 校验器,`ctx` 上可注入业务服务。
1616
- MQTT 5 RPC:`app.request()` + `ctx.reply()`
17+
- MQTT 5 共享订阅(`$share/<group>/<filter>`),原生支持多实例扇出。
18+
- 路由级 `timeout` / `concurrency` 护栏,触发后通过 `onError` 阶段上报。
19+
- `app.onMetric()` 在每次 dispatch / publish 完成时发结构化事件,方便接 Prometheus / OpenTelemetry。
1720
- `app.on()` 监听 broker lifecycle events;`app.publish()` 让 worker 主动推送消息。
1821
- 适配器:`@mqttkit/aedes`(TCP + WebSocket)与 `@mqttkit/asyncapi`(AsyncAPI 3.0 文档)。
1922
- 内存版 `TestBroker` 用于单测。面向 Bun 与 TypeScript。

0 commit comments

Comments
 (0)