node-server-engine 1.12.3 → 1.13.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.
|
@@ -1,24 +1,38 @@
|
|
|
1
1
|
import { Attributes } from '@google-cloud/pubsub';
|
|
2
2
|
import { PubSubAddSubscriberOptions, PubSubMessageHandler, PubSubPublisherOptions } from './PubSub.types';
|
|
3
|
+
/**
|
|
4
|
+
* This is a singleton service who's role is to manage pub/sub connections
|
|
5
|
+
* It is the preferred way to interact with Pub/Sub as it manages the underlying subscription and handler objects
|
|
6
|
+
* It avoids potential subscription splitting on an instance
|
|
7
|
+
*/
|
|
3
8
|
export declare const PubSub: {
|
|
4
9
|
/**
|
|
5
|
-
*
|
|
10
|
+
* Initialize the registered publishers and subscribers
|
|
6
11
|
*/
|
|
7
12
|
init(): Promise<void>;
|
|
8
13
|
/**
|
|
9
|
-
* Shutdown
|
|
14
|
+
* Shutdown the registered publishers and subscribers
|
|
10
15
|
*/
|
|
11
16
|
shutdown(): Promise<void>;
|
|
12
17
|
/**
|
|
13
|
-
*
|
|
18
|
+
* Creates a publisher if it does not exist yet
|
|
19
|
+
* @param topic - Topic name or array of topic names
|
|
20
|
+
* @param options - Publisher configuration options
|
|
14
21
|
*/
|
|
15
22
|
addPublisher(topic: string | Array<string>, options?: PubSubPublisherOptions): void;
|
|
16
23
|
/**
|
|
17
|
-
*
|
|
24
|
+
* Add message handlers to a subscription
|
|
25
|
+
* @param subscription - Name of the Pub/Sub subscription
|
|
26
|
+
* @param handler - Function or list of functions to set as message handlers
|
|
27
|
+
* @param options - Indicates that the additional options need to handle on Subscriber
|
|
18
28
|
*/
|
|
19
|
-
addSubscriber<T>(
|
|
29
|
+
addSubscriber<T>(subscription: string, handler: PubSubMessageHandler<T> | Array<PubSubMessageHandler<T>>, options?: PubSubAddSubscriberOptions): void;
|
|
20
30
|
/**
|
|
21
|
-
*
|
|
31
|
+
* Send a message to a Pub/Sub topic
|
|
32
|
+
* @param topic - Name of the topic
|
|
33
|
+
* @param message - Content of the message, must be an object that can be JSON stringified
|
|
34
|
+
* @param attributes - Attributes for this message, can be used to filter messages on the subscription
|
|
35
|
+
* @param orderingKey - Enforce order guarantee of messages sent with the same key
|
|
22
36
|
*/
|
|
23
37
|
publish(topic: string, message: unknown, attributes?: Attributes, orderingKey?: string): Promise<void>;
|
|
24
38
|
};
|
|
@@ -10,108 +10,151 @@ var _EngineError = require("../EngineError");
|
|
|
10
10
|
var _LifecycleController = require("../LifecycleController");
|
|
11
11
|
var _utils = require("../../utils");
|
|
12
12
|
const namespace = 'engine:PubSub';
|
|
13
|
-
const
|
|
14
|
-
const
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
13
|
+
const RETRYABLE_ERROR_CODES = new Set([4, 8, 10, 13, 14]); // DEADLINE_EXCEEDED, RESOURCE_EXHAUSTED, ABORTED, INTERNAL, UNAVAILABLE
|
|
14
|
+
const resolvedProjectId = process.env.GOOGLE_CLOUD_PROJECT || process.env.GCLOUD_PROJECT || process.env.GCP_PROJECT_ID;
|
|
15
|
+
function isRetryableInitError(error) {
|
|
16
|
+
const err = error;
|
|
17
|
+
const message = (err?.message ?? '').toLowerCase();
|
|
18
|
+
const code = typeof err?.code === 'string' ? Number.parseInt(err.code, 10) : err?.code;
|
|
19
|
+
return typeof code === 'number' && RETRYABLE_ERROR_CODES.has(code) || message.includes('deadline exceeded') || message.includes('timed out') || message.includes('timeout') || message.includes('unavailable') || message.includes('resource exhausted');
|
|
20
|
+
}
|
|
21
|
+
async function withRetry(operationName, fn) {
|
|
22
|
+
const maxAttempts = Math.max(1, Number.parseInt(process.env.PUBSUB_INIT_MAX_ATTEMPTS ?? '4', 10));
|
|
23
|
+
const baseDelayMs = Math.max(100, Number.parseInt(process.env.PUBSUB_INIT_RETRY_BASE_DELAY_MS ?? '1000', 10));
|
|
24
|
+
const maxDelayMs = Math.max(baseDelayMs, Number.parseInt(process.env.PUBSUB_INIT_RETRY_MAX_DELAY_MS ?? '10000', 10));
|
|
20
25
|
let lastError;
|
|
21
|
-
for (let
|
|
26
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
22
27
|
try {
|
|
23
28
|
return await fn();
|
|
24
|
-
} catch (
|
|
25
|
-
lastError =
|
|
26
|
-
|
|
29
|
+
} catch (error) {
|
|
30
|
+
lastError = error;
|
|
31
|
+
if (!isRetryableInitError(error) || attempt === maxAttempts) {
|
|
32
|
+
throw error;
|
|
33
|
+
}
|
|
34
|
+
const delayMs = Math.min(baseDelayMs * 2 ** (attempt - 1), maxDelayMs);
|
|
35
|
+
(0, _utils.reportError)({
|
|
36
|
+
namespace,
|
|
37
|
+
message: `Retrying Pub/Sub init operation '${operationName}'`,
|
|
38
|
+
error: {
|
|
39
|
+
attempt,
|
|
40
|
+
maxAttempts,
|
|
41
|
+
delayMs,
|
|
42
|
+
reason: error instanceof Error ? error.message : String(error)
|
|
43
|
+
}
|
|
44
|
+
});
|
|
45
|
+
await new Promise(resolve => setTimeout(resolve, delayMs));
|
|
27
46
|
}
|
|
28
47
|
}
|
|
29
|
-
throw lastError;
|
|
30
|
-
}
|
|
48
|
+
throw lastError instanceof Error ? lastError : new Error(`Pub/Sub init operation '${operationName}' failed after retries`);
|
|
49
|
+
}
|
|
31
50
|
|
|
32
51
|
/**
|
|
33
|
-
*
|
|
52
|
+
* Associative containing all the subscriptions sorted by topic registered for publishing
|
|
34
53
|
*/
|
|
35
|
-
const
|
|
36
|
-
apiEndpoint: 'pubsub.googleapis.com'
|
|
37
|
-
});
|
|
54
|
+
const subscriptions = {};
|
|
38
55
|
|
|
39
|
-
/**
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
handlers,
|
|
47
|
-
isDebezium
|
|
48
|
-
} = entry;
|
|
49
|
-
(0, _utils.reportDebug)({
|
|
50
|
-
namespace,
|
|
51
|
-
message: `Reattaching subscription '${subscriptionName}'`
|
|
52
|
-
});
|
|
56
|
+
/**
|
|
57
|
+
* Associative containing all the topics registered for publishing
|
|
58
|
+
*/
|
|
59
|
+
const topics = {};
|
|
60
|
+
const pubSubClient = new _pubsub.PubSub(resolvedProjectId ? {
|
|
61
|
+
projectId: resolvedProjectId
|
|
62
|
+
} : undefined);
|
|
53
63
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
});
|
|
60
|
-
subscription.on('error', error => {
|
|
61
|
-
(0, _utils.reportError)(error);
|
|
62
|
-
// Reconnect on transient errors (DEADLINE_EXCEEDED, UNAVAILABLE, INTERNAL)
|
|
63
|
-
const code = error?.code;
|
|
64
|
-
if (code === 4 || code === 14 || code === 13) {
|
|
65
|
-
reattachSubscription(subscriptionName, Math.min(delayMs * 2, 60000));
|
|
66
|
-
}
|
|
67
|
-
});
|
|
68
|
-
}, delayMs);
|
|
69
|
-
}
|
|
64
|
+
/**
|
|
65
|
+
* This is a singleton service who's role is to manage pub/sub connections
|
|
66
|
+
* It is the preferred way to interact with Pub/Sub as it manages the underlying subscription and handler objects
|
|
67
|
+
* It avoids potential subscription splitting on an instance
|
|
68
|
+
*/
|
|
70
69
|
const PubSub = exports.PubSub = {
|
|
71
70
|
/**
|
|
72
|
-
*
|
|
71
|
+
* Initialize the registered publishers and subscribers
|
|
73
72
|
*/
|
|
74
73
|
async init() {
|
|
75
74
|
(0, _utils.reportDebug)({
|
|
76
75
|
namespace,
|
|
77
|
-
message: `Initializing Pub/Sub
|
|
76
|
+
message: `Initializing Pub/Sub`
|
|
78
77
|
});
|
|
79
|
-
|
|
78
|
+
if (!resolvedProjectId) {
|
|
79
|
+
(0, _utils.reportDebug)({
|
|
80
|
+
namespace,
|
|
81
|
+
message: 'Pub/Sub projectId not set in env, relying on ADC auto-detection'
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
const skipValidation = process.env.PUBSUB_SKIP_VALIDATION?.toLowerCase() === 'true';
|
|
85
|
+
// Check that all topics/permissions exist, and that we have permission on them
|
|
86
|
+
if (!skipValidation) {
|
|
87
|
+
await Promise.all([
|
|
88
|
+
// Test that all topics actually exist and that we have permissions
|
|
89
|
+
...Object.values(topics).map(async topic => {
|
|
90
|
+
const [exists] = await withRetry(`topic.exists:${topic.name}`, async () => topic.exists());
|
|
91
|
+
if (!exists) throw new _EngineError.EngineError(`Topic ${topic.name} does not exist`);
|
|
92
|
+
// Test permission ton publish to topic
|
|
93
|
+
const [permissions] = await withRetry(`topic.permissions:${topic.name}`, async () => topic.iam.testPermissions(['pubsub.topics.publish']));
|
|
94
|
+
const hasPermissions = Object.values(permissions).every(success => success);
|
|
95
|
+
if (!hasPermissions) throw new _EngineError.EngineError(`Instance does not have appropriate permissions to publish to topic ${topic.name}`);
|
|
96
|
+
}),
|
|
97
|
+
// Test that all subscriptions actually exist and that we have permissions
|
|
98
|
+
...Object.values(subscriptions).map(async ({
|
|
99
|
+
subscription
|
|
100
|
+
}) => {
|
|
101
|
+
const [exists] = await withRetry(`subscription.exists:${subscription.name}`, async () => subscription.exists());
|
|
102
|
+
if (!exists) throw new _EngineError.EngineError(`Subscription ${subscription.name} does not exist`);
|
|
103
|
+
// Test permission ton consume subscription
|
|
104
|
+
const [permissions] = await withRetry(`subscription.permissions:${subscription.name}`, async () => subscription.iam.testPermissions(['pubsub.subscriptions.consume']));
|
|
105
|
+
const hasPermissions = Object.values(permissions).every(success => success);
|
|
106
|
+
if (!hasPermissions) throw new _EngineError.EngineError(`Instance does not have appropriate permissions to subscribe to subscription ${subscription.name}`);
|
|
107
|
+
})]);
|
|
108
|
+
} else {
|
|
109
|
+
(0, _utils.reportDebug)({
|
|
110
|
+
namespace,
|
|
111
|
+
message: 'Skipping Pub/Sub existence and permission validation (PUBSUB_SKIP_VALIDATION=true)'
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
// Register handlers on the subscriptions to activate them
|
|
116
|
+
for (const {
|
|
80
117
|
subscription,
|
|
81
118
|
handlers,
|
|
82
119
|
isDebezium
|
|
83
|
-
}
|
|
120
|
+
} of Object.values(subscriptions)) {
|
|
84
121
|
subscription.on('message', message => {
|
|
85
|
-
(0, _handleMessage.handleMessage)(message, subscription, handlers, isDebezium).catch(
|
|
122
|
+
(0, _handleMessage.handleMessage)(message, subscription, handlers, isDebezium).catch(error => {
|
|
123
|
+
(0, _utils.reportError)(error);
|
|
124
|
+
});
|
|
86
125
|
});
|
|
87
126
|
subscription.on('error', error => {
|
|
88
|
-
(0, _utils.reportError)(
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
}
|
|
127
|
+
(0, _utils.reportError)({
|
|
128
|
+
namespace,
|
|
129
|
+
message: `Pub/Sub subscription stream error on '${subscription.name}'`,
|
|
130
|
+
error
|
|
131
|
+
});
|
|
94
132
|
});
|
|
95
133
|
}
|
|
96
134
|
_LifecycleController.LifecycleController.register(PubSub);
|
|
97
135
|
},
|
|
98
136
|
/**
|
|
99
|
-
* Shutdown
|
|
137
|
+
* Shutdown the registered publishers and subscribers
|
|
100
138
|
*/
|
|
101
139
|
async shutdown() {
|
|
102
140
|
(0, _utils.reportDebug)({
|
|
103
141
|
namespace,
|
|
104
142
|
message: `Shutting down Pub/Sub`
|
|
105
143
|
});
|
|
144
|
+
// Flush all pending messages and shut down connections
|
|
106
145
|
await Promise.all([...Object.values(topics).map(async topic => topic.flush()), ...Object.values(subscriptions).map(async ({
|
|
107
146
|
subscription
|
|
108
147
|
}) => subscription.close())]);
|
|
148
|
+
// Delete the stored topics/subscriptions
|
|
109
149
|
Object.keys(topics).forEach(topic => delete topics[topic]);
|
|
110
150
|
Object.keys(subscriptions).forEach(subscription => delete subscriptions[subscription]);
|
|
151
|
+
// Close the client
|
|
111
152
|
await pubSubClient.close();
|
|
112
153
|
},
|
|
113
154
|
/**
|
|
114
|
-
*
|
|
155
|
+
* Creates a publisher if it does not exist yet
|
|
156
|
+
* @param topic - Topic name or array of topic names
|
|
157
|
+
* @param options - Publisher configuration options
|
|
115
158
|
*/
|
|
116
159
|
addPublisher(topic, options) {
|
|
117
160
|
const topicArray = topic instanceof Array ? topic : [topic];
|
|
@@ -120,68 +163,104 @@ const PubSub = exports.PubSub = {
|
|
|
120
163
|
message: `Registering publisher for topics '${topicArray.join("', '")}'`,
|
|
121
164
|
data: options
|
|
122
165
|
});
|
|
166
|
+
// Register a new topic if it does not exist yet
|
|
123
167
|
for (const topic of topicArray) {
|
|
124
|
-
if (!topics
|
|
168
|
+
if (!Object.keys(topics).includes(topic)) {
|
|
125
169
|
topics[topic] = pubSubClient.topic(topic, {
|
|
126
170
|
enableOpenTelemetryTracing: true,
|
|
127
171
|
messageOrdering: options?.enableMessageOrdering ?? false,
|
|
128
172
|
batching: options?.batching ? {
|
|
129
173
|
maxMessages: options.batching.maxMessages ?? 100,
|
|
130
174
|
maxBytes: options.batching.maxBytes ?? 1024 * 1024,
|
|
175
|
+
// 1MB
|
|
131
176
|
maxMilliseconds: options.batching.maxMilliseconds ?? 100
|
|
177
|
+
} : undefined,
|
|
178
|
+
gaxOpts: options?.retry ? {
|
|
179
|
+
retry: {
|
|
180
|
+
retryCodes: [10, 14],
|
|
181
|
+
// ABORTED, UNAVAILABLE
|
|
182
|
+
backoffSettings: {
|
|
183
|
+
initialRetryDelayMillis: options.retry.initialDelayMillis ?? 100,
|
|
184
|
+
maxRetryDelayMillis: options.retry.maxDelayMillis ?? 60000,
|
|
185
|
+
retryDelayMultiplier: options.retry.delayMultiplier ?? 1.3,
|
|
186
|
+
initialRpcTimeoutMillis: 60000,
|
|
187
|
+
maxRpcTimeoutMillis: 600000,
|
|
188
|
+
rpcTimeoutMultiplier: 1.0,
|
|
189
|
+
totalTimeoutMillis: 600000
|
|
190
|
+
}
|
|
191
|
+
}
|
|
132
192
|
} : undefined
|
|
133
193
|
});
|
|
134
194
|
}
|
|
135
195
|
}
|
|
136
196
|
},
|
|
137
197
|
/**
|
|
138
|
-
*
|
|
198
|
+
* Add message handlers to a subscription
|
|
199
|
+
* @param subscription - Name of the Pub/Sub subscription
|
|
200
|
+
* @param handler - Function or list of functions to set as message handlers
|
|
201
|
+
* @param options - Indicates that the additional options need to handle on Subscriber
|
|
139
202
|
*/
|
|
140
|
-
addSubscriber(
|
|
203
|
+
addSubscriber(subscription, handler, options = {}) {
|
|
141
204
|
const handlers = handler instanceof Array ? handler : [handler];
|
|
205
|
+
const isDebezium = options?.isDebezium ?? false;
|
|
206
|
+
const first = options?.first ?? false;
|
|
207
|
+
const flowControl = options?.flowControl;
|
|
208
|
+
const ackDeadline = options?.ackDeadline;
|
|
142
209
|
(0, _utils.reportDebug)({
|
|
143
210
|
namespace,
|
|
144
|
-
message: `Registering subscriber '${
|
|
145
|
-
data:
|
|
211
|
+
message: `Registering subscriber for subscription '${subscription}'`,
|
|
212
|
+
data: {
|
|
213
|
+
first,
|
|
214
|
+
handlersCount: handlers.length,
|
|
215
|
+
isDebezium,
|
|
216
|
+
flowControl
|
|
217
|
+
}
|
|
146
218
|
});
|
|
147
|
-
if (!subscriptions
|
|
148
|
-
subscriptions[
|
|
149
|
-
subscription: pubSubClient.subscription(
|
|
219
|
+
if (!Object.keys(subscriptions).includes(subscription)) {
|
|
220
|
+
subscriptions[subscription] = {
|
|
221
|
+
subscription: pubSubClient.subscription(subscription, {
|
|
150
222
|
enableOpenTelemetryTracing: true,
|
|
151
|
-
flowControl:
|
|
223
|
+
flowControl: flowControl ? {
|
|
224
|
+
maxMessages: flowControl.maxMessages ?? 1000,
|
|
225
|
+
maxBytes: flowControl.maxBytes ?? 100 * 1024 * 1024,
|
|
226
|
+
// 100MB
|
|
227
|
+
allowExcessMessages: flowControl.allowExcessMessages ?? true
|
|
228
|
+
} : {
|
|
152
229
|
maxMessages: 1000,
|
|
153
230
|
maxBytes: 100 * 1024 * 1024,
|
|
154
231
|
allowExcessMessages: true
|
|
155
232
|
},
|
|
156
|
-
ackDeadline:
|
|
233
|
+
ackDeadline: ackDeadline ?? 60
|
|
157
234
|
}),
|
|
158
|
-
handlers: []
|
|
159
|
-
isDebezium: options?.isDebezium ?? false
|
|
235
|
+
handlers: []
|
|
160
236
|
};
|
|
161
237
|
}
|
|
162
|
-
if (
|
|
238
|
+
if (isDebezium) subscriptions[subscription].isDebezium = true;
|
|
239
|
+
if (first) subscriptions[subscription].handlers.push(...handlers);else subscriptions[subscription].handlers.unshift(...handlers);
|
|
163
240
|
},
|
|
164
241
|
/**
|
|
165
|
-
*
|
|
242
|
+
* Send a message to a Pub/Sub topic
|
|
243
|
+
* @param topic - Name of the topic
|
|
244
|
+
* @param message - Content of the message, must be an object that can be JSON stringified
|
|
245
|
+
* @param attributes - Attributes for this message, can be used to filter messages on the subscription
|
|
246
|
+
* @param orderingKey - Enforce order guarantee of messages sent with the same key
|
|
166
247
|
*/
|
|
167
248
|
async publish(topic, message, attributes, orderingKey) {
|
|
168
|
-
if (!topics[topic]) {
|
|
169
|
-
throw new _EngineError.EngineError(`No publisher registered for topic '${topic}'`);
|
|
170
|
-
}
|
|
249
|
+
if (!topics[topic]) throw new _EngineError.EngineError(`No publisher was registered for topic '${topic}'`);
|
|
171
250
|
(0, _utils.reportDebug)({
|
|
172
251
|
namespace,
|
|
173
|
-
message: `
|
|
252
|
+
message: `Sending message to topic '${topic}'`,
|
|
174
253
|
data: {
|
|
175
254
|
message,
|
|
176
255
|
attributes,
|
|
177
256
|
orderingKey
|
|
178
257
|
}
|
|
179
258
|
});
|
|
180
|
-
await
|
|
259
|
+
await topics[topic].publishMessage({
|
|
181
260
|
json: message,
|
|
182
261
|
attributes,
|
|
183
262
|
orderingKey
|
|
184
|
-
})
|
|
263
|
+
});
|
|
185
264
|
}
|
|
186
265
|
};
|
|
187
266
|
//# sourceMappingURL=PubSub.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"PubSub.js","names":["_pubsub","require","_handleMessage","_EngineError","_LifecycleController","_utils","namespace","subscriptions","topics","withRetry","fn","retries","delay","lastError","i","err","Promise","res","setTimeout","pubSubClient","PubsubClient","apiEndpoint","reattachSubscription","subscriptionName","delayMs","entry","subscription","handlers","isDebezium","reportDebug","message","removeAllListeners","on","handleMessage","catch","reportError","error","code","Math","min","PubSub","exports","init","Object","entries","LifecycleController","register","shutdown","all","values","map","topic","flush","close","keys","forEach","addPublisher","options","topicArray","Array","join","data","enableOpenTelemetryTracing","messageOrdering","enableMessageOrdering","batching","maxMessages","maxBytes","maxMilliseconds","undefined","addSubscriber","handler","flowControl","allowExcessMessages","ackDeadline","first","push","unshift","publish","attributes","orderingKey","EngineError","publishMessage","json"],"sources":["../../../src/entities/PubSub/PubSub.ts"],"sourcesContent":["import {\n Attributes,\n PubSub as PubsubClient,\n Message\n} from '@google-cloud/pubsub';\nimport { handleMessage } from './handleMessage';\nimport {\n PubSubTopicsMap,\n PubSubSubscriptionsMap,\n PubSubAddSubscriberOptions,\n PubSubMessageHandler,\n PubSubPublisherOptions\n} from './PubSub.types';\nimport { EngineError } from 'entities/EngineError';\nimport { LifecycleController } from 'entities/LifecycleController';\nimport { reportDebug, reportError } from 'utils';\n\nconst namespace = 'engine:PubSub';\n\nconst subscriptions: PubSubSubscriptionsMap = {};\nconst topics: PubSubTopicsMap = {};\n\n/**\n * Add basic retry wrapper\n */\nconst withRetry = async <T>(\n fn: () => Promise<T>,\n retries = 3,\n delay = 500\n): Promise<T> => {\n let lastError: any;\n for (let i = 0; i < retries; i++) {\n try {\n return await fn();\n } catch (err) {\n lastError = err;\n await new Promise((res) => setTimeout(res, delay * (i + 1)));\n }\n }\n throw lastError;\n};\n\n/**\n * PubSub client with safer defaults\n */\nconst pubSubClient = new PubsubClient({\n apiEndpoint: 'pubsub.googleapis.com'\n});\n\n/** Re-open a subscription's message stream after a transient error */\nfunction reattachSubscription(subscriptionName: string, delayMs = 5000): void {\n setTimeout(() => {\n const entry = subscriptions[subscriptionName];\n if (!entry) return;\n const { subscription, handlers, isDebezium } = entry;\n\n reportDebug({ namespace, message: `Reattaching subscription '${subscriptionName}'` });\n\n // Remove all existing listeners before re-adding to avoid duplicates\n subscription.removeAllListeners('message');\n subscription.removeAllListeners('error');\n\n subscription.on('message', (message) => {\n handleMessage(message as Message, subscription, handlers, isDebezium).catch(reportError);\n });\n\n subscription.on('error', (error) => {\n reportError(error);\n // Reconnect on transient errors (DEADLINE_EXCEEDED, UNAVAILABLE, INTERNAL)\n const code = (error as any)?.code;\n if (code === 4 || code === 14 || code === 13) {\n reattachSubscription(subscriptionName, Math.min(delayMs * 2, 60000));\n }\n });\n }, delayMs);\n}\n\nexport const PubSub = {\n /**\n * ✅ FAST + NON-BLOCKING INIT\n */\n async init(): Promise<void> {\n reportDebug({ namespace, message: `Initializing Pub/Sub (safe mode)` });\n\n for (const [subscriptionName, { subscription, handlers, isDebezium }] of Object.entries(\n subscriptions\n )) {\n subscription.on('message', (message) => {\n handleMessage(\n message as Message,\n subscription,\n handlers,\n isDebezium\n ).catch(reportError);\n });\n\n subscription.on('error', (error) => {\n reportError(error);\n // Auto-reconnect on transient gRPC errors (DEADLINE_EXCEEDED=4, UNAVAILABLE=14, INTERNAL=13)\n const code = (error as any)?.code;\n if (code === 4 || code === 14 || code === 13) {\n reattachSubscription(subscriptionName, 5000);\n }\n });\n }\n\n LifecycleController.register(PubSub);\n },\n\n /**\n * Shutdown\n */\n async shutdown(): Promise<void> {\n reportDebug({ namespace, message: `Shutting down Pub/Sub` });\n\n await Promise.all([\n ...Object.values(topics).map(async (topic) => topic.flush()),\n ...Object.values(subscriptions).map(async ({ subscription }) =>\n subscription.close()\n )\n ]);\n\n Object.keys(topics).forEach((topic) => delete topics[topic]);\n Object.keys(subscriptions).forEach(\n (subscription) => delete subscriptions[subscription]\n );\n\n await pubSubClient.close();\n },\n\n /**\n * Publisher registration\n */\n addPublisher(\n topic: string | Array<string>,\n options?: PubSubPublisherOptions\n ): void {\n const topicArray = topic instanceof Array ? topic : [topic];\n\n reportDebug({\n namespace,\n message: `Registering publisher for topics '${topicArray.join(\"', '\")}'`,\n data: options\n });\n\n for (const topic of topicArray) {\n if (!topics[topic]) {\n topics[topic] = pubSubClient.topic(topic, {\n enableOpenTelemetryTracing: true,\n messageOrdering: options?.enableMessageOrdering ?? false,\n batching: options?.batching\n ? {\n maxMessages: options.batching.maxMessages ?? 100,\n maxBytes: options.batching.maxBytes ?? 1024 * 1024,\n maxMilliseconds: options.batching.maxMilliseconds ?? 100\n }\n : undefined\n });\n }\n }\n },\n\n /**\n * Subscriber registration\n */\n addSubscriber<T>(\n subscriptionName: string,\n handler: PubSubMessageHandler<T> | Array<PubSubMessageHandler<T>>,\n options: PubSubAddSubscriberOptions = {}\n ): void {\n const handlers = handler instanceof Array ? handler : [handler];\n\n reportDebug({\n namespace,\n message: `Registering subscriber '${subscriptionName}'`,\n data: options\n });\n\n if (!subscriptions[subscriptionName]) {\n subscriptions[subscriptionName] = {\n subscription: pubSubClient.subscription(subscriptionName, {\n enableOpenTelemetryTracing: true,\n flowControl: options.flowControl ?? {\n maxMessages: 1000,\n maxBytes: 100 * 1024 * 1024,\n allowExcessMessages: true\n },\n ackDeadline: options.ackDeadline ?? 60\n }),\n handlers: [],\n isDebezium: options?.isDebezium ?? false\n };\n }\n\n if (options.first)\n subscriptions[subscriptionName].handlers.push(...handlers);\n else subscriptions[subscriptionName].handlers.unshift(...handlers);\n },\n\n /**\n * ✅ SAFE PUBLISH (with retry)\n */\n async publish(\n topic: string,\n message: unknown,\n attributes?: Attributes,\n orderingKey?: string\n ): Promise<void> {\n if (!topics[topic]) {\n throw new EngineError(`No publisher registered for topic '${topic}'`);\n }\n\n reportDebug({\n namespace,\n message: `Publishing to '${topic}'`,\n data: { message, attributes, orderingKey }\n });\n\n await withRetry(() =>\n topics[topic].publishMessage({\n json: message,\n attributes,\n orderingKey\n })\n );\n }\n};"],"mappings":"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","ignoreList":[]}
|
|
1
|
+
{"version":3,"file":"PubSub.js","names":["_pubsub","require","_handleMessage","_EngineError","_LifecycleController","_utils","namespace","RETRYABLE_ERROR_CODES","Set","resolvedProjectId","process","env","GOOGLE_CLOUD_PROJECT","GCLOUD_PROJECT","GCP_PROJECT_ID","isRetryableInitError","error","err","message","toLowerCase","code","Number","parseInt","has","includes","withRetry","operationName","fn","maxAttempts","Math","max","PUBSUB_INIT_MAX_ATTEMPTS","baseDelayMs","PUBSUB_INIT_RETRY_BASE_DELAY_MS","maxDelayMs","PUBSUB_INIT_RETRY_MAX_DELAY_MS","lastError","attempt","delayMs","min","reportError","reason","Error","String","Promise","resolve","setTimeout","subscriptions","topics","pubSubClient","PubsubClient","projectId","undefined","PubSub","exports","init","reportDebug","skipValidation","PUBSUB_SKIP_VALIDATION","all","Object","values","map","topic","exists","name","EngineError","permissions","iam","testPermissions","hasPermissions","every","success","subscription","handlers","isDebezium","on","handleMessage","catch","LifecycleController","register","shutdown","flush","close","keys","forEach","addPublisher","options","topicArray","Array","join","data","enableOpenTelemetryTracing","messageOrdering","enableMessageOrdering","batching","maxMessages","maxBytes","maxMilliseconds","gaxOpts","retry","retryCodes","backoffSettings","initialRetryDelayMillis","initialDelayMillis","maxRetryDelayMillis","maxDelayMillis","retryDelayMultiplier","delayMultiplier","initialRpcTimeoutMillis","maxRpcTimeoutMillis","rpcTimeoutMultiplier","totalTimeoutMillis","addSubscriber","handler","first","flowControl","ackDeadline","handlersCount","length","allowExcessMessages","push","unshift","publish","attributes","orderingKey","publishMessage","json"],"sources":["../../../src/entities/PubSub/PubSub.ts"],"sourcesContent":["import {\n Attributes,\n PubSub as PubsubClient,\n Message\n} from '@google-cloud/pubsub';\nimport { handleMessage } from './handleMessage';\nimport {\n PubSubTopicsMap,\n PubSubSubscriptionsMap,\n PubSubAddSubscriberOptions,\n PubSubMessageHandler,\n PubSubPublisherOptions\n} from './PubSub.types';\nimport { EngineError } from 'entities/EngineError';\nimport { LifecycleController } from 'entities/LifecycleController';\nimport { reportDebug, reportError } from 'utils';\n\nconst namespace = 'engine:PubSub';\nconst RETRYABLE_ERROR_CODES = new Set([4, 8, 10, 13, 14]); // DEADLINE_EXCEEDED, RESOURCE_EXHAUSTED, ABORTED, INTERNAL, UNAVAILABLE\nconst resolvedProjectId =\n process.env.GOOGLE_CLOUD_PROJECT ||\n process.env.GCLOUD_PROJECT ||\n process.env.GCP_PROJECT_ID;\n\nfunction isRetryableInitError(error: unknown): boolean {\n const err = error as { code?: number | string; message?: string } | undefined;\n const message = (err?.message ?? '').toLowerCase();\n const code =\n typeof err?.code === 'string' ? Number.parseInt(err.code, 10) : err?.code;\n return (\n (typeof code === 'number' && RETRYABLE_ERROR_CODES.has(code)) ||\n message.includes('deadline exceeded') ||\n message.includes('timed out') ||\n message.includes('timeout') ||\n message.includes('unavailable') ||\n message.includes('resource exhausted')\n );\n}\n\nasync function withRetry<T>(\n operationName: string,\n fn: () => Promise<T>\n): Promise<T> {\n const maxAttempts = Math.max(\n 1,\n Number.parseInt(process.env.PUBSUB_INIT_MAX_ATTEMPTS ?? '4', 10)\n );\n const baseDelayMs = Math.max(\n 100,\n Number.parseInt(process.env.PUBSUB_INIT_RETRY_BASE_DELAY_MS ?? '1000', 10)\n );\n const maxDelayMs = Math.max(\n baseDelayMs,\n Number.parseInt(process.env.PUBSUB_INIT_RETRY_MAX_DELAY_MS ?? '10000', 10)\n );\n let lastError: unknown;\n\n for (let attempt = 1; attempt <= maxAttempts; attempt++) {\n try {\n return await fn();\n } catch (error) {\n lastError = error;\n if (!isRetryableInitError(error) || attempt === maxAttempts) {\n throw error;\n }\n const delayMs = Math.min(baseDelayMs * 2 ** (attempt - 1), maxDelayMs);\n reportError({\n namespace,\n message: `Retrying Pub/Sub init operation '${operationName}'`,\n error: {\n attempt,\n maxAttempts,\n delayMs,\n reason: error instanceof Error ? error.message : String(error)\n }\n });\n await new Promise((resolve) => setTimeout(resolve, delayMs));\n }\n }\n\n throw lastError instanceof Error\n ? lastError\n : new Error(\n `Pub/Sub init operation '${operationName}' failed after retries`\n );\n}\n\n/**\n * Associative containing all the subscriptions sorted by topic registered for publishing\n */\nconst subscriptions: PubSubSubscriptionsMap = {};\n\n/**\n * Associative containing all the topics registered for publishing\n */\nconst topics: PubSubTopicsMap = {};\n\nconst pubSubClient = new PubsubClient(\n resolvedProjectId ? { projectId: resolvedProjectId } : undefined\n);\n\n/**\n * This is a singleton service who's role is to manage pub/sub connections\n * It is the preferred way to interact with Pub/Sub as it manages the underlying subscription and handler objects\n * It avoids potential subscription splitting on an instance\n */\nexport const PubSub = {\n /**\n * Initialize the registered publishers and subscribers\n */\n async init(): Promise<void> {\n reportDebug({ namespace, message: `Initializing Pub/Sub` });\n if (!resolvedProjectId) {\n reportDebug({\n namespace,\n message:\n 'Pub/Sub projectId not set in env, relying on ADC auto-detection'\n });\n }\n const skipValidation =\n process.env.PUBSUB_SKIP_VALIDATION?.toLowerCase() === 'true';\n // Check that all topics/permissions exist, and that we have permission on them\n if (!skipValidation) {\n await Promise.all([\n // Test that all topics actually exist and that we have permissions\n ...Object.values(topics).map(async (topic) => {\n const [exists] = await withRetry(\n `topic.exists:${topic.name}`,\n async () => topic.exists()\n );\n if (!exists)\n throw new EngineError(`Topic ${topic.name} does not exist`);\n // Test permission ton publish to topic\n const [permissions] = await withRetry(\n `topic.permissions:${topic.name}`,\n async () => topic.iam.testPermissions(['pubsub.topics.publish'])\n );\n const hasPermissions = Object.values(permissions).every(\n (success) => success\n );\n if (!hasPermissions)\n throw new EngineError(\n `Instance does not have appropriate permissions to publish to topic ${topic.name}`\n );\n }),\n // Test that all subscriptions actually exist and that we have permissions\n ...Object.values(subscriptions).map(async ({ subscription }) => {\n const [exists] = await withRetry(\n `subscription.exists:${subscription.name}`,\n async () => subscription.exists()\n );\n if (!exists)\n throw new EngineError(\n `Subscription ${subscription.name} does not exist`\n );\n // Test permission ton consume subscription\n const [permissions] = await withRetry(\n `subscription.permissions:${subscription.name}`,\n async () =>\n subscription.iam.testPermissions(['pubsub.subscriptions.consume'])\n );\n const hasPermissions = Object.values(permissions).every(\n (success) => success\n );\n if (!hasPermissions)\n throw new EngineError(\n `Instance does not have appropriate permissions to subscribe to subscription ${subscription.name}`\n );\n })\n ]);\n } else {\n reportDebug({\n namespace,\n message:\n 'Skipping Pub/Sub existence and permission validation (PUBSUB_SKIP_VALIDATION=true)'\n });\n }\n\n // Register handlers on the subscriptions to activate them\n for (const { subscription, handlers, isDebezium } of Object.values(\n subscriptions\n )) {\n subscription.on('message', (message) => {\n handleMessage(\n message as Message,\n subscription,\n handlers,\n isDebezium\n ).catch((error) => {\n reportError(error);\n });\n });\n subscription.on('error', (error) => {\n reportError({\n namespace,\n message: `Pub/Sub subscription stream error on '${subscription.name}'`,\n error\n });\n });\n }\n\n LifecycleController.register(PubSub);\n },\n\n /**\n * Shutdown the registered publishers and subscribers\n */\n async shutdown(): Promise<void> {\n reportDebug({ namespace, message: `Shutting down Pub/Sub` });\n // Flush all pending messages and shut down connections\n await Promise.all([\n ...Object.values(topics).map(async (topic) => topic.flush()),\n ...Object.values(subscriptions).map(async ({ subscription }) =>\n subscription.close()\n )\n ]);\n // Delete the stored topics/subscriptions\n Object.keys(topics).forEach((topic) => delete topics[topic]);\n Object.keys(subscriptions).forEach(\n (subscription) => delete subscriptions[subscription]\n );\n // Close the client\n await pubSubClient.close();\n },\n\n /**\n * Creates a publisher if it does not exist yet\n * @param topic - Topic name or array of topic names\n * @param options - Publisher configuration options\n */\n addPublisher(\n topic: string | Array<string>,\n options?: PubSubPublisherOptions\n ): void {\n const topicArray = topic instanceof Array ? topic : [topic];\n reportDebug({\n namespace,\n message: `Registering publisher for topics '${topicArray.join(\"', '\")}'`,\n data: options\n });\n // Register a new topic if it does not exist yet\n for (const topic of topicArray) {\n if (!Object.keys(topics).includes(topic)) {\n topics[topic] = pubSubClient.topic(topic, {\n enableOpenTelemetryTracing: true,\n messageOrdering: options?.enableMessageOrdering ?? false,\n batching: options?.batching\n ? {\n maxMessages: options.batching.maxMessages ?? 100,\n maxBytes: options.batching.maxBytes ?? 1024 * 1024, // 1MB\n maxMilliseconds: options.batching.maxMilliseconds ?? 100\n }\n : undefined,\n gaxOpts: options?.retry\n ? {\n retry: {\n retryCodes: [10, 14], // ABORTED, UNAVAILABLE\n backoffSettings: {\n initialRetryDelayMillis:\n options.retry.initialDelayMillis ?? 100,\n maxRetryDelayMillis: options.retry.maxDelayMillis ?? 60000,\n retryDelayMultiplier: options.retry.delayMultiplier ?? 1.3,\n initialRpcTimeoutMillis: 60000,\n maxRpcTimeoutMillis: 600000,\n rpcTimeoutMultiplier: 1.0,\n totalTimeoutMillis: 600000\n }\n }\n }\n : undefined\n });\n }\n }\n },\n\n /**\n * Add message handlers to a subscription\n * @param subscription - Name of the Pub/Sub subscription\n * @param handler - Function or list of functions to set as message handlers\n * @param options - Indicates that the additional options need to handle on Subscriber\n */\n addSubscriber<T>(\n subscription: string,\n handler: PubSubMessageHandler<T> | Array<PubSubMessageHandler<T>>,\n options: PubSubAddSubscriberOptions = {}\n ): void {\n const handlers = handler instanceof Array ? handler : [handler];\n const isDebezium = options?.isDebezium ?? false;\n const first = options?.first ?? false;\n const flowControl = options?.flowControl;\n const ackDeadline = options?.ackDeadline;\n\n reportDebug({\n namespace,\n message: `Registering subscriber for subscription '${subscription}'`,\n data: {\n first,\n handlersCount: handlers.length,\n isDebezium,\n flowControl\n }\n });\n if (!Object.keys(subscriptions).includes(subscription)) {\n subscriptions[subscription] = {\n subscription: pubSubClient.subscription(subscription, {\n enableOpenTelemetryTracing: true,\n flowControl: flowControl\n ? {\n maxMessages: flowControl.maxMessages ?? 1000,\n maxBytes: flowControl.maxBytes ?? 100 * 1024 * 1024, // 100MB\n allowExcessMessages: flowControl.allowExcessMessages ?? true\n }\n : {\n maxMessages: 1000,\n maxBytes: 100 * 1024 * 1024,\n allowExcessMessages: true\n },\n ackDeadline: ackDeadline ?? 60\n }),\n handlers: []\n };\n }\n\n if (isDebezium) subscriptions[subscription].isDebezium = true;\n\n if (first) subscriptions[subscription].handlers.push(...handlers);\n else subscriptions[subscription].handlers.unshift(...handlers);\n },\n\n /**\n * Send a message to a Pub/Sub topic\n * @param topic - Name of the topic\n * @param message - Content of the message, must be an object that can be JSON stringified\n * @param attributes - Attributes for this message, can be used to filter messages on the subscription\n * @param orderingKey - Enforce order guarantee of messages sent with the same key\n */\n async publish(\n topic: string,\n message: unknown,\n attributes?: Attributes,\n orderingKey?: string\n ): Promise<void> {\n if (!topics[topic])\n throw new EngineError(`No publisher was registered for topic '${topic}'`);\n reportDebug({\n namespace,\n message: `Sending message to topic '${topic}'`,\n data: { message, attributes, orderingKey }\n });\n await topics[topic].publishMessage({\n json: message,\n attributes,\n orderingKey\n });\n }\n};\n"],"mappings":"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","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "node-server-engine",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.13.0",
|
|
4
4
|
"description": "Framework used to develop backend services. This package ships with a lot of features to standardize the creation of services, letting you focus on the business logic.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"scripts": {
|