pulse-sdk 0.0.4 → 0.0.5
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/dist/config.d.ts +1 -0
- package/dist/config.js +5 -0
- package/dist/consumer.d.ts +1 -1
- package/dist/consumer.js +37 -12
- package/dist/consumerManager.d.ts +4 -2
- package/dist/consumerManager.js +21 -12
- package/dist/message.d.ts +1 -1
- package/dist/message.js +1 -1
- package/package.json +1 -1
package/dist/config.d.ts
CHANGED
package/dist/config.js
CHANGED
|
@@ -14,6 +14,7 @@ const DEFAULTS = {
|
|
|
14
14
|
grpcUrl: 'localhost:50052',
|
|
15
15
|
eventTypes: ['events'],
|
|
16
16
|
grouped: true,
|
|
17
|
+
autoCommit: true,
|
|
17
18
|
};
|
|
18
19
|
function loadConfig(configPath) {
|
|
19
20
|
const candidates = [
|
|
@@ -40,12 +41,16 @@ function loadConfig(configPath) {
|
|
|
40
41
|
envCfg.consumerName = process.env.PULSE_CONSUMER_NAME;
|
|
41
42
|
if (process.env.PULSE_GROUPED)
|
|
42
43
|
envCfg.grouped = process.env.PULSE_GROUPED === 'true';
|
|
44
|
+
if (process.env.PULSE_AUTOCOMMIT)
|
|
45
|
+
envCfg.autoCommit = process.env.PULSE_AUTOCOMMIT === 'true';
|
|
43
46
|
const merged = Object.assign({}, DEFAULTS, fileCfg, envCfg);
|
|
44
47
|
// Ensure eventTypes array exists
|
|
45
48
|
if (!merged.eventTypes)
|
|
46
49
|
merged.eventTypes = DEFAULTS.eventTypes;
|
|
47
50
|
if (merged.grouped === undefined)
|
|
48
51
|
merged.grouped = true;
|
|
52
|
+
if (merged.autoCommit === undefined)
|
|
53
|
+
merged.autoCommit = true;
|
|
49
54
|
return merged;
|
|
50
55
|
}
|
|
51
56
|
// Initialize topics from config using gRPC CreateTopic RPC.
|
package/dist/consumer.d.ts
CHANGED
package/dist/consumer.js
CHANGED
|
@@ -28,15 +28,25 @@ class Consumer {
|
|
|
28
28
|
const handlers = this.handlers[topicName] || [];
|
|
29
29
|
for (const h of handlers) {
|
|
30
30
|
const unregister = (0, consumerManager_1.registerSharedHandler)(this.config.grpcUrl, topicName, consumerName, (msg, stub, offset) => {
|
|
31
|
-
// run handler with context so commit() works
|
|
31
|
+
// run handler with context so commit() works and support auto-commit
|
|
32
32
|
// debug: console.log('consumer.wrapper.invoke', consumerName, topicName);
|
|
33
|
-
(
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
33
|
+
(async () => {
|
|
34
|
+
await (0, message_1.runWithContext)({ stub: stub || this.client, topic: topicName, consumerName, offset: offset ?? msg.offset }, async () => {
|
|
35
|
+
try {
|
|
36
|
+
const r = h(msg);
|
|
37
|
+
if (r && typeof r.then === 'function')
|
|
38
|
+
await r;
|
|
39
|
+
}
|
|
40
|
+
catch (e) { /* ignore */ }
|
|
41
|
+
if (this.config.autoCommit !== false) {
|
|
42
|
+
try {
|
|
43
|
+
await (0, message_1.commit)();
|
|
44
|
+
}
|
|
45
|
+
catch (_) { /* ignore commit errors */ }
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
})().catch(() => { });
|
|
49
|
+
}, { autoCommit: this.config.autoCommit });
|
|
40
50
|
this.unregisterFns.push(unregister);
|
|
41
51
|
}
|
|
42
52
|
// Return a promise that never resolves (stream runs until process exits)
|
|
@@ -69,12 +79,27 @@ class Consumer {
|
|
|
69
79
|
const handlers = this.handlers[req.topic] || [];
|
|
70
80
|
for (const h of handlers) {
|
|
71
81
|
// run handler within AsyncLocalStorage context so commit() can access stub and offset
|
|
72
|
-
(
|
|
82
|
+
(async () => {
|
|
73
83
|
try {
|
|
74
|
-
|
|
84
|
+
await (0, message_1.runWithContext)({ stub: this.client, topic: req.topic, consumerName, offset: message.offset }, async () => {
|
|
85
|
+
try {
|
|
86
|
+
const r = h(message);
|
|
87
|
+
if (r && typeof r.then === 'function')
|
|
88
|
+
await r;
|
|
89
|
+
}
|
|
90
|
+
catch (e) { /* handler error ignored here */ }
|
|
91
|
+
if (this.config.autoCommit !== false) {
|
|
92
|
+
try {
|
|
93
|
+
await (0, message_1.commit)();
|
|
94
|
+
}
|
|
95
|
+
catch (_) { /* ignore commit errors */ }
|
|
96
|
+
}
|
|
97
|
+
});
|
|
75
98
|
}
|
|
76
|
-
catch (
|
|
77
|
-
|
|
99
|
+
catch (err) {
|
|
100
|
+
// ignore
|
|
101
|
+
}
|
|
102
|
+
})().catch(() => { });
|
|
78
103
|
}
|
|
79
104
|
});
|
|
80
105
|
const p = new Promise((resolve, reject) => {
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
type Handler = (msg: any) =>
|
|
1
|
+
type Handler = (msg: any) => any;
|
|
2
2
|
export declare function shutdownAll(): Promise<void>;
|
|
3
|
-
export declare function registerSharedHandler(grpcUrl: string, topic: string, consumerName: string, handler: Handler
|
|
3
|
+
export declare function registerSharedHandler(grpcUrl: string, topic: string, consumerName: string, handler: Handler, opts?: {
|
|
4
|
+
autoCommit?: boolean;
|
|
5
|
+
}): () => void;
|
|
4
6
|
export {};
|
package/dist/consumerManager.js
CHANGED
|
@@ -46,12 +46,12 @@ const registry = new Map();
|
|
|
46
46
|
function keyFor(grpcUrl, topic, consumerName) {
|
|
47
47
|
return `${grpcUrl}::${topic}::${consumerName}`;
|
|
48
48
|
}
|
|
49
|
-
function registerSharedHandler(grpcUrl, topic, consumerName, handler) {
|
|
49
|
+
function registerSharedHandler(grpcUrl, topic, consumerName, handler, opts) {
|
|
50
50
|
const k = keyFor(grpcUrl, topic, consumerName);
|
|
51
51
|
let entry = registry.get(k);
|
|
52
52
|
if (!entry) {
|
|
53
53
|
const client = (0, client_1.createClient)(grpcUrl);
|
|
54
|
-
entry = { topic, consumerName, client, stream: null, handlers: new Set(), nextIndex: 0, grpcUrl };
|
|
54
|
+
entry = { topic, consumerName, client, stream: null, handlers: new Set(), nextIndex: 0, grpcUrl, autoCommit: opts?.autoCommit !== false };
|
|
55
55
|
// add handler before starting the stream to avoid losing early messages
|
|
56
56
|
entry.handlers.add(handler);
|
|
57
57
|
registry.set(k, entry);
|
|
@@ -106,16 +106,25 @@ function startStream(entry) {
|
|
|
106
106
|
entry.nextIndex = 0;
|
|
107
107
|
const h = handlers[entry.nextIndex % handlers.length];
|
|
108
108
|
entry.nextIndex = (entry.nextIndex + 1) % handlers.length;
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
109
|
+
// run handler inside context providing the stub for commit(); support async handlers
|
|
110
|
+
(async () => {
|
|
111
|
+
try {
|
|
112
|
+
await (0, message_1.runWithContext)({ stub: entry.client, topic: entry.topic, consumerName: entry.consumerName, offset: message.offset }, async () => {
|
|
113
|
+
const r = h(message);
|
|
114
|
+
if (r && typeof r.then === 'function')
|
|
115
|
+
await r;
|
|
116
|
+
if (entry.autoCommit) {
|
|
117
|
+
try {
|
|
118
|
+
await (0, message_1.commit)();
|
|
119
|
+
}
|
|
120
|
+
catch (err) { /* ignore commit errors here */ }
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
}
|
|
124
|
+
catch (e) {
|
|
125
|
+
console.warn('handler error', e);
|
|
126
|
+
}
|
|
127
|
+
})().catch(() => { });
|
|
119
128
|
});
|
|
120
129
|
stream.on('error', (e) => {
|
|
121
130
|
// Log once and clean up the registry entry to avoid reconnect storms and test leaks
|
package/dist/message.d.ts
CHANGED
|
@@ -11,7 +11,7 @@ interface MessageContext {
|
|
|
11
11
|
offset: number;
|
|
12
12
|
committed?: boolean;
|
|
13
13
|
}
|
|
14
|
-
export declare function runWithContext(ctx: MessageContext, fn: () => void):
|
|
14
|
+
export declare function runWithContext(ctx: MessageContext, fn: () => void): unknown;
|
|
15
15
|
export declare function getContext(): MessageContext | undefined;
|
|
16
16
|
export declare function commit(): Promise<void>;
|
|
17
17
|
export declare class Message implements IMessage {
|
package/dist/message.js
CHANGED
|
@@ -7,7 +7,7 @@ exports.commit = commit;
|
|
|
7
7
|
const async_hooks_1 = require("async_hooks");
|
|
8
8
|
const storage = new async_hooks_1.AsyncLocalStorage();
|
|
9
9
|
function runWithContext(ctx, fn) {
|
|
10
|
-
storage.run(ctx, fn);
|
|
10
|
+
return storage.run(ctx, fn);
|
|
11
11
|
}
|
|
12
12
|
function getContext() {
|
|
13
13
|
return storage.getStore();
|