@beignet/provider-event-bus-redis 0.0.49 → 0.0.50

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  # @beignet/provider-event-bus-redis
2
2
 
3
+ ## 0.0.50
4
+
5
+ ### Patch Changes
6
+
7
+ - 6fe026a: Expose event-subscription readiness and asynchronous cleanup, await listener
8
+ registries during provider startup with bounded rollback, diagnose unsafe app
9
+ wiring, and make Redis subscription lifecycle failures observable with bounded
10
+ provider shutdown and recoverable channel state.
11
+
3
12
  ## 0.0.49
4
13
 
5
14
  ### Patch Changes
package/README.md CHANGED
@@ -68,6 +68,7 @@ The provider reads environment variables with the `REDIS_EVENT_BUS_` prefix:
68
68
  | `REDIS_EVENT_BUS_DB` | No | Redis database number. Defaults to `0`. | `0` |
69
69
  | `REDIS_EVENT_BUS_CHANNEL_PREFIX` | No | Prefix for Pub/Sub channels. Defaults to `beignet:event-bus:`. | `my-app:events:` |
70
70
  | `REDIS_EVENT_BUS_CONNECT_TIMEOUT_MS` | No | Initial connection timeout in milliseconds. Defaults to `5000`. | `2000` |
71
+ | `REDIS_EVENT_BUS_CLEANUP_TIMEOUT_MS` | No | Shutdown deadline for subscription cleanup in milliseconds. Defaults to `10000`. | `5000` |
71
72
  | `REDIS_EVENT_BUS_MAX_RETRIES_PER_REQUEST` | No | Per-command retry limit before a command rejects. Defaults to `2`. | `1` |
72
73
  | `REDIS_EVENT_BUS_CONNECT_MAX_ATTEMPTS` | No | Connection attempts before startup fails. Defaults to `3`. | `5` |
73
74
 
@@ -83,6 +84,7 @@ import { createRedisEventBusProvider } from "@beignet/provider-event-bus-redis";
83
84
  const provider = createRedisEventBusProvider({
84
85
  channelPrefix: "my-app:events:",
85
86
  connectTimeoutMs: 2000,
87
+ cleanupTimeoutMs: 5000,
86
88
  maxRetriesPerRequest: 1,
87
89
  db: 1,
88
90
  retryStrategy: (times) => Math.min(times * 100, 1000),
@@ -131,7 +133,17 @@ Use `createRedisEventBus(...)` when your app owns Redis clients:
131
133
 
132
134
  ```typescript
133
135
  import Redis from "ioredis";
136
+ import { defineEvent } from "@beignet/core/events";
134
137
  import { createRedisEventBus } from "@beignet/provider-event-bus-redis";
138
+ import { z } from "zod";
139
+
140
+ const UserRegistered = defineEvent("user.registered", {
141
+ payload: z.object({ userId: z.string() }),
142
+ });
143
+
144
+ function handleUserRegistered(payload: { userId: string }) {
145
+ console.log(`Registered ${payload.userId}`);
146
+ }
135
147
 
136
148
  const publisher = new Redis(process.env.REDIS_EVENT_BUS_URL);
137
149
  const subscriber = new Redis(process.env.REDIS_EVENT_BUS_URL);
@@ -141,25 +153,47 @@ const eventBus = createRedisEventBus({
141
153
  channelPrefix: "my-app:events:",
142
154
  });
143
155
 
156
+ const subscription = eventBus.subscribe(UserRegistered, handleUserRegistered);
157
+ await subscription.ready;
158
+
144
159
  // During app shutdown:
145
- await eventBus.stop();
146
- await Promise.all([publisher.quit(), subscriber.quit()]);
160
+ try {
161
+ await eventBus.stop();
162
+ await Promise.all([publisher.quit(), subscriber.quit()]);
163
+ } catch (error) {
164
+ subscriber.disconnect();
165
+ publisher.disconnect();
166
+ throw error;
167
+ }
147
168
  ```
148
169
 
149
- Register listeners during startup before handling traffic. The `EventBusPort`
150
- subscription API is synchronous, while Redis subscription acknowledgement is
151
- asynchronous, so messages published immediately after a new subscription may be
152
- missed during startup races. Await `stop()` to detach Beignet's message
153
- listener, cancel pending subscription retries, and best-effort unsubscribe the
154
- channels registered through that adapter. It does not close the caller-owned
155
- Redis clients. Stopping is terminal for that adapter: later subscription
156
- attempts reject instead of creating handlers that cannot receive messages.
170
+ Register listeners during startup before handling traffic and await each
171
+ subscription's `ready` promise. It resolves after Redis acknowledges the
172
+ channel subscription. Failed subscription commands retry with capped backoff
173
+ while a local handler remains; callers can own a deadline, and
174
+ `registerListeners(...)` applies one 10-second deadline to a complete registry
175
+ by default. Readiness proves initial registration only and does not change
176
+ Pub/Sub's online-only delivery semantics.
177
+
178
+ Await `unsubscribe()` when removing an individual handler. During adapter
179
+ shutdown, `stop()` closes all remaining subscriptions, detaches local delivery,
180
+ cancels pending retries, and awaits channel cleanup. Cleanup errors reject and
181
+ are instrumented; `stop()` retries channels left dirty by an earlier
182
+ unsubscribe before reporting any remaining failure. To keep lifecycle rollback
183
+ bounded, `stop()` rejects after `cleanupTimeoutMs` (10 seconds by default) even
184
+ if an ioredis command never settles. The adapter does not close caller-owned
185
+ Redis clients, so force-disconnect them when cleanup rejects. Stopping is
186
+ terminal: later subscription attempts reject instead of creating handlers that
187
+ cannot receive messages.
157
188
 
158
189
  ## Delivery semantics
159
190
 
160
191
  - `publish(...)` publishes one Redis Pub/Sub message on
161
192
  `<channelPrefix><event.name>`.
162
193
  - Only subscribers that are online and currently subscribed receive the event.
194
+ - A subscription's `ready` promise resolves only after the initial Redis
195
+ subscription acknowledgement. Cancelling before acknowledgement rejects that
196
+ promise and prevents future local delivery.
163
197
  - ioredis resubscribes after a transient reconnect, but messages published
164
198
  during the disconnected interval are not recovered.
165
199
  - Payloads are JSON encoded and delivered to handlers without persisting the
package/dist/index.d.ts CHANGED
@@ -14,6 +14,7 @@ export interface RedisEventBusConfig {
14
14
  DB?: number;
15
15
  CHANNEL_PREFIX: string;
16
16
  CONNECT_TIMEOUT_MS: number;
17
+ CLEANUP_TIMEOUT_MS: number;
17
18
  MAX_RETRIES_PER_REQUEST: number;
18
19
  CONNECT_MAX_ATTEMPTS: number;
19
20
  }
@@ -57,6 +58,8 @@ export interface CreateRedisEventBusOptions {
57
58
  publisher: RedisEventBusPublisherClient;
58
59
  subscriber: RedisEventBusSubscriberClient;
59
60
  channelPrefix?: string;
61
+ /** Maximum time to await subscription cleanup before `stop()` rejects. */
62
+ cleanupTimeoutMs?: number;
60
63
  instrumentation?: ProviderInstrumentationTarget;
61
64
  onHandlerError?: (error: unknown, eventName: string, payload: unknown) => void;
62
65
  onSubscriberError?: (error: unknown) => void;
@@ -64,6 +67,8 @@ export interface CreateRedisEventBusOptions {
64
67
  export interface CreateRedisEventBusProviderOptions {
65
68
  channelPrefix?: string;
66
69
  connectTimeoutMs?: number;
70
+ /** Maximum time to await subscription cleanup before forcing disconnect. */
71
+ cleanupTimeoutMs?: number;
67
72
  maxRetriesPerRequest?: number;
68
73
  retryStrategy?: (times: number) => number | null;
69
74
  db?: number;
@@ -77,8 +82,8 @@ export interface CreateRedisEventBusProviderOptions {
77
82
  */
78
83
  export interface RedisEventBus extends EventBusPort {
79
84
  /**
80
- * Stop local delivery and best-effort unsubscribe the adapter's channels
81
- * without closing the caller-owned Redis clients.
85
+ * Stop local delivery and await cleanup of the adapter's channels without
86
+ * closing the caller-owned Redis clients.
82
87
  */
83
88
  stop(): Promise<void>;
84
89
  }
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}