@lad-tech/nsc-toolkit 1.21.0 → 1.22.0
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 +2 -2
- package/dist/Client.js +33 -8
- package/dist/StreamFetcher.js +20 -0
- package/dist/StreamManager.js +39 -4
- package/dist/types/Client.d.ts +3 -1
- package/dist/types/StreamFetcher.d.ts +16 -0
- package/dist/types/StreamManager.d.ts +6 -2
- package/dist/types/interfaces.d.ts +9 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# [1.
|
|
1
|
+
# [1.22.0](https://github.com/lad-tech/nsc-toolkit/compare/v1.21.0...v1.22.0) (2024-08-14)
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
### Features
|
|
5
5
|
|
|
6
|
-
* Add
|
|
6
|
+
* Add support pull consumer ([#110](https://github.com/lad-tech/nsc-toolkit/issues/110)) ([ed77ad7](https://github.com/lad-tech/nsc-toolkit/commit/ed77ad7fa0542c0e8d0b56e71b430a14672bafae))
|
package/dist/Client.js
CHANGED
|
@@ -36,12 +36,29 @@ class Client extends Root_1.Root {
|
|
|
36
36
|
message.ack = event.ack.bind(event);
|
|
37
37
|
message.nak = event.nak.bind(event);
|
|
38
38
|
}
|
|
39
|
-
listener.emit(
|
|
39
|
+
listener.emit(eventName, message);
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async startBatchWatch(fetcher, listener, eventName) {
|
|
43
|
+
while (true) {
|
|
44
|
+
const batch = [];
|
|
45
|
+
const events = fetcher.fetch();
|
|
46
|
+
for await (const event of events) {
|
|
47
|
+
let data;
|
|
48
|
+
try {
|
|
49
|
+
data = (0, nats_1.JSONCodec)().decode(event.data);
|
|
50
|
+
}
|
|
51
|
+
catch (error) {
|
|
52
|
+
data = (0, nats_1.StringCodec)().decode(event.data);
|
|
53
|
+
}
|
|
54
|
+
const message = { data };
|
|
55
|
+
message.ack = event.ack.bind(event);
|
|
56
|
+
message.nak = event.nak.bind(event);
|
|
57
|
+
batch.push(message);
|
|
58
|
+
}
|
|
59
|
+
listener.emit(eventName, batch);
|
|
40
60
|
}
|
|
41
61
|
}
|
|
42
|
-
/**
|
|
43
|
-
* Make listener for service events. Auto subscribe and unsubscribe to subject
|
|
44
|
-
*/
|
|
45
62
|
getListener(serviceNameFrom, options) {
|
|
46
63
|
if (!this.events) {
|
|
47
64
|
throw new Error('The service does not generate events');
|
|
@@ -73,7 +90,12 @@ class Client extends Root_1.Root {
|
|
|
73
90
|
subscription = this.broker.subscribe(`${this.serviceName}.${eventName}`, queue);
|
|
74
91
|
}
|
|
75
92
|
this.subscriptions.set(eventName, subscription);
|
|
76
|
-
|
|
93
|
+
if (StreamManager_1.StreamManager.isStreamFetcher(subscription) && StreamManager_1.StreamManager.isPullConsumerOptions(options)) {
|
|
94
|
+
this.startBatchWatch(subscription, listener, String(eventName));
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
this.startWatch(subscription, listener, String(eventName));
|
|
98
|
+
}
|
|
77
99
|
return method.call(target, eventName, handler);
|
|
78
100
|
}
|
|
79
101
|
catch (error) {
|
|
@@ -182,7 +204,8 @@ class Client extends Root_1.Root {
|
|
|
182
204
|
return (0, nats_1.JSONCodec)().decode(result.data);
|
|
183
205
|
}
|
|
184
206
|
catch (error) {
|
|
185
|
-
|
|
207
|
+
const errorMessage = new Error(`${error === null || error === void 0 ? void 0 : error.message}. Subject: ${subject} `);
|
|
208
|
+
return this.buildErrorMessage(errorMessage);
|
|
186
209
|
}
|
|
187
210
|
}
|
|
188
211
|
async makeHttpRequest(subject, message, options, timeout) {
|
|
@@ -219,11 +242,13 @@ class Client extends Root_1.Root {
|
|
|
219
242
|
resolve(JSON.parse(responseDataString));
|
|
220
243
|
}
|
|
221
244
|
catch (error) {
|
|
222
|
-
|
|
245
|
+
const errorMessage = new Error(`${error === null || error === void 0 ? void 0 : error.message}. Subject: ${subject} `);
|
|
246
|
+
resolve(this.buildErrorMessage(errorMessage));
|
|
223
247
|
}
|
|
224
248
|
});
|
|
225
249
|
request.on('error', error => {
|
|
226
|
-
|
|
250
|
+
const errorMessage = new Error(`${error === null || error === void 0 ? void 0 : error.message}. Subject: ${subject} `);
|
|
251
|
+
resolve(this.buildErrorMessage(errorMessage));
|
|
227
252
|
});
|
|
228
253
|
if (this.isStream(message.payload)) {
|
|
229
254
|
message.payload.pipe(request);
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StreamFetcher = void 0;
|
|
4
|
+
class StreamFetcher {
|
|
5
|
+
constructor(jsClient, streamName, consumerName, options) {
|
|
6
|
+
this.jsClient = jsClient;
|
|
7
|
+
this.streamName = streamName;
|
|
8
|
+
this.consumerName = consumerName;
|
|
9
|
+
this.options = options;
|
|
10
|
+
}
|
|
11
|
+
fetch(noWait, size, expires) {
|
|
12
|
+
return this.jsClient.fetch(this.streamName, this.consumerName, {
|
|
13
|
+
batch: size !== null && size !== void 0 ? size : this.options.batchSize,
|
|
14
|
+
expires: expires !== null && expires !== void 0 ? expires : this.options.batchTimeout,
|
|
15
|
+
no_wait: noWait !== null && noWait !== void 0 ? noWait : this.options.noWait,
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
exports.StreamFetcher = StreamFetcher;
|
|
20
|
+
//# sourceMappingURL=StreamFetcher.js.map
|
package/dist/StreamManager.js
CHANGED
|
@@ -3,6 +3,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.StreamManager = void 0;
|
|
4
4
|
const nats_1 = require("nats");
|
|
5
5
|
const Root_1 = require("./Root");
|
|
6
|
+
const jsconsumeropts_1 = require("nats/lib/nats-base-client/jsconsumeropts");
|
|
7
|
+
const StreamFetcher_1 = require("./StreamFetcher");
|
|
6
8
|
class StreamManager extends Root_1.Root {
|
|
7
9
|
constructor(param) {
|
|
8
10
|
super(param.broker, param.outputFormatter);
|
|
@@ -21,6 +23,12 @@ class StreamManager extends Root_1.Root {
|
|
|
21
23
|
rollUps: true,
|
|
22
24
|
};
|
|
23
25
|
}
|
|
26
|
+
static isPullConsumerOptions(setting) {
|
|
27
|
+
return !!(setting === null || setting === void 0 ? void 0 : setting.batch);
|
|
28
|
+
}
|
|
29
|
+
static isStreamFetcher(consumer) {
|
|
30
|
+
return !!(consumer === null || consumer === void 0 ? void 0 : consumer.fetch);
|
|
31
|
+
}
|
|
24
32
|
async createStreams() {
|
|
25
33
|
if (!this.jsm) {
|
|
26
34
|
this.jsm = await this.param.broker.jetstreamManager();
|
|
@@ -55,14 +63,29 @@ class StreamManager extends Root_1.Root {
|
|
|
55
63
|
async createConsumer(serviceNameFrom, eventName, setting) {
|
|
56
64
|
const consumerName = this.capitalizeFirstLetter(serviceNameFrom) + this.capitalizeFirstLetter(eventName);
|
|
57
65
|
const prefix = this.param.options.prefix;
|
|
58
|
-
const
|
|
66
|
+
const subject = `${this.param.serviceName}.${prefix}.${eventName}`;
|
|
67
|
+
if (!this.jsm) {
|
|
68
|
+
this.jsm = await this.param.broker.jetstreamManager();
|
|
69
|
+
}
|
|
59
70
|
const options = (0, nats_1.consumerOpts)();
|
|
71
|
+
const isPullConsumer = StreamManager.isPullConsumerOptions(setting);
|
|
60
72
|
options
|
|
61
73
|
.durable(consumerName)
|
|
62
74
|
.manualAck()
|
|
63
75
|
.ackExplicit()
|
|
64
|
-
.
|
|
65
|
-
.
|
|
76
|
+
.filterSubject(subject)
|
|
77
|
+
.maxAckPending((setting === null || setting === void 0 ? void 0 : setting.maxPending) || 10);
|
|
78
|
+
if (!isPullConsumer) {
|
|
79
|
+
options.deliverTo((0, nats_1.createInbox)());
|
|
80
|
+
}
|
|
81
|
+
if (isPullConsumer) {
|
|
82
|
+
if (setting.maxPullRequestExpires) {
|
|
83
|
+
options.maxPullRequestExpires(setting.maxPullRequestExpires);
|
|
84
|
+
}
|
|
85
|
+
if (setting.maxPullRequestBatch) {
|
|
86
|
+
options.maxPullBatch(setting.maxPullRequestBatch);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
66
89
|
if (setting === null || setting === void 0 ? void 0 : setting.maxAckWaiting) {
|
|
67
90
|
options.ackWait(setting.maxAckWaiting);
|
|
68
91
|
}
|
|
@@ -77,7 +100,19 @@ class StreamManager extends Root_1.Root {
|
|
|
77
100
|
options.deliverAll();
|
|
78
101
|
}
|
|
79
102
|
}
|
|
80
|
-
|
|
103
|
+
const streamName = await this.jsm.streams.find(subject);
|
|
104
|
+
if (!streamName) {
|
|
105
|
+
throw new Error(`Error creating consumer ${consumerName}. Stream for subject ${subject} not found`);
|
|
106
|
+
}
|
|
107
|
+
if ((0, jsconsumeropts_1.isConsumerOptsBuilder)(options)) {
|
|
108
|
+
await this.jsm.consumers.add(streamName, options.config);
|
|
109
|
+
}
|
|
110
|
+
return isPullConsumer
|
|
111
|
+
? new StreamFetcher_1.StreamFetcher(this.broker.jetstream(), streamName, consumerName, {
|
|
112
|
+
batchSize: setting.maxPullRequestBatch,
|
|
113
|
+
batchTimeout: setting.maxPullRequestExpires,
|
|
114
|
+
})
|
|
115
|
+
: this.broker.jetstream().subscribe(subject, options);
|
|
81
116
|
}
|
|
82
117
|
getStreamName(eventName) {
|
|
83
118
|
const serviceName = this.capitalizeFirstLetter(this.param.serviceName);
|
package/dist/types/Client.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/// <reference types="node" />
|
|
2
2
|
import { Readable } from 'node:stream';
|
|
3
|
-
import { ClientParam, Emitter, GetListenerOptions, Listener, MethodSettings } from './interfaces';
|
|
3
|
+
import { ClientParam, Emitter, GetBatchListenerOptions, GetListenerOptions, Listener, ListenerBatch, MethodSettings } from './interfaces';
|
|
4
4
|
import { Root } from './Root';
|
|
5
5
|
type RequestData = Record<string, unknown> | Readable;
|
|
6
6
|
export declare class Client<E extends Emitter = Emitter> extends Root {
|
|
@@ -13,10 +13,12 @@ export declare class Client<E extends Emitter = Emitter> extends Root {
|
|
|
13
13
|
private REQUEST_HTTP_SETTINGS_TIMEOUT;
|
|
14
14
|
constructor({ broker, events, loggerOutputFormatter, serviceName, baggage, cache, Ref }: ClientParam<E>);
|
|
15
15
|
private startWatch;
|
|
16
|
+
private startBatchWatch;
|
|
16
17
|
/**
|
|
17
18
|
* Make listener for service events. Auto subscribe and unsubscribe to subject
|
|
18
19
|
*/
|
|
19
20
|
getListener<A extends keyof E>(serviceNameFrom: string, options?: GetListenerOptions): Listener<E>;
|
|
21
|
+
getListener<A extends keyof E>(serviceNameFrom: string, options?: GetBatchListenerOptions): ListenerBatch<E>;
|
|
20
22
|
private createCacheKey;
|
|
21
23
|
private validate;
|
|
22
24
|
protected request<R = any, P extends RequestData = RequestData>(subject: string, data: P, { options, request, response }: MethodSettings): Promise<R>;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import { JetStreamClient, JsMsg } from 'nats';
|
|
2
|
+
import { QueuedIterator } from 'nats/lib/nats-base-client/queued_iterator';
|
|
3
|
+
interface BatcherOptions {
|
|
4
|
+
batchSize?: number;
|
|
5
|
+
batchTimeout?: number;
|
|
6
|
+
noWait?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare class StreamFetcher {
|
|
9
|
+
private jsClient;
|
|
10
|
+
private streamName;
|
|
11
|
+
private consumerName;
|
|
12
|
+
private options;
|
|
13
|
+
constructor(jsClient: JetStreamClient, streamName: string, consumerName: string, options: BatcherOptions);
|
|
14
|
+
fetch(noWait?: boolean, size?: number, expires?: number): QueuedIterator<JsMsg>;
|
|
15
|
+
}
|
|
16
|
+
export {};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
import { StreamManagerParam, GetListenerOptions } from '.';
|
|
2
|
-
import { JetStreamSubscription } from 'nats';
|
|
1
|
+
import { StreamManagerParam, GetListenerOptions, GetBatchListenerOptions } from '.';
|
|
2
|
+
import { JetStreamSubscription, Subscription } from 'nats';
|
|
3
3
|
import { Root } from './Root';
|
|
4
|
+
import { StreamFetcher } from './StreamFetcher';
|
|
4
5
|
export declare class StreamManager extends Root {
|
|
5
6
|
private param;
|
|
6
7
|
private readonly STAR_WILDCARD;
|
|
@@ -10,8 +11,11 @@ export declare class StreamManager extends Root {
|
|
|
10
11
|
private readonly defaultStreamOption;
|
|
11
12
|
private jsm?;
|
|
12
13
|
constructor(param: StreamManagerParam);
|
|
14
|
+
static isPullConsumerOptions(setting?: GetListenerOptions | GetBatchListenerOptions): setting is GetBatchListenerOptions;
|
|
15
|
+
static isStreamFetcher(consumer?: JetStreamSubscription | StreamFetcher | Subscription): consumer is StreamFetcher;
|
|
13
16
|
createStreams(): Promise<void>;
|
|
14
17
|
createConsumer(serviceNameFrom: string, eventName: string, setting?: GetListenerOptions): Promise<JetStreamSubscription>;
|
|
18
|
+
createConsumer(serviceNameFrom: string, eventName: string, setting?: GetBatchListenerOptions): Promise<StreamFetcher>;
|
|
15
19
|
private getStreamName;
|
|
16
20
|
private isNotFoundStreamError;
|
|
17
21
|
private buildPrefixForStreamName;
|
|
@@ -71,6 +71,11 @@ export interface GetListenerOptions {
|
|
|
71
71
|
maxPending?: number;
|
|
72
72
|
maxAckWaiting?: number;
|
|
73
73
|
}
|
|
74
|
+
export interface GetBatchListenerOptions extends GetListenerOptions {
|
|
75
|
+
batch: true;
|
|
76
|
+
maxPullRequestBatch?: number;
|
|
77
|
+
maxPullRequestExpires?: number;
|
|
78
|
+
}
|
|
74
79
|
export interface StreamManagerParam {
|
|
75
80
|
serviceName: string;
|
|
76
81
|
options: StreamOptions;
|
|
@@ -129,6 +134,10 @@ export interface Listener<E extends Emitter> {
|
|
|
129
134
|
on<A extends keyof E>(action: A, handler: E[A]): void;
|
|
130
135
|
off<A extends keyof E>(action: A, handler: E[A]): void;
|
|
131
136
|
}
|
|
137
|
+
export interface ListenerBatch<E extends Emitter> {
|
|
138
|
+
on<A extends keyof E>(action: A, handler: (params: Array<Parameters<E[A]>[0]>) => void): void;
|
|
139
|
+
off<A extends keyof E>(action: A, handler: (params: Array<Parameters<E[A]>[0]>) => void): void;
|
|
140
|
+
}
|
|
132
141
|
export interface HttpSettings {
|
|
133
142
|
ip?: string;
|
|
134
143
|
port?: number;
|