elasticio-sailor-nodejs 3.0.0-dev7.1 → 3.0.0-sailor-proxy-dev1
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/.eslintrc.js +12 -146
- package/.nsprc +0 -8
- package/CHANGELOG.md +0 -10
- package/config/local.json +19 -0
- package/lib/executor.js +0 -9
- package/lib/proxy-client.js +725 -0
- package/lib/sailor.js +73 -205
- package/lib/settings.js +17 -20
- package/lib/utils.js +8 -0
- package/mise.toml +2 -0
- package/package.json +8 -6
- package/run.js +14 -22
- package/run.local.js +14 -0
- package/tsconfig.json +23 -0
- package/lib/amqp.js +0 -647
- package/lib/messagesDB.js +0 -37
package/lib/sailor.js
CHANGED
|
@@ -1,28 +1,22 @@
|
|
|
1
1
|
const uuid = require('uuid');
|
|
2
2
|
const ComponentReader = require('./component_reader.js').ComponentReader;
|
|
3
|
-
const
|
|
3
|
+
const { ProxyClient, MESSAGE_PROCESSING_STATUS } = require('./proxy-client.js');
|
|
4
4
|
const TaskExec = require('./executor.js').TaskExec;
|
|
5
5
|
const log = require('./logging.js');
|
|
6
6
|
const _ = require('lodash');
|
|
7
7
|
const hooksData = require('./hooksData');
|
|
8
|
-
const Encryptor = require('../lib/encryptor');
|
|
9
8
|
const RestApiClient = require('elasticio-rest-node');
|
|
10
9
|
const assert = require('assert');
|
|
11
10
|
const co = require('co');
|
|
12
|
-
const pThrottle = require('p-throttle');
|
|
13
|
-
const { ObjectStorage } = require('@elastic.io/maester-client');
|
|
14
|
-
const { Readable } = require('stream');
|
|
15
|
-
const messagesDB = require('./messagesDB.js');
|
|
16
11
|
|
|
17
|
-
const AMQP_HEADER_META_PREFIX = 'x-eio-meta-';
|
|
18
12
|
const OBJECT_ID_HEADER = 'x-ipaas-object-storage-id';
|
|
19
13
|
|
|
20
|
-
function
|
|
21
|
-
return _.mapKeys(settings, (value, key) => _.
|
|
14
|
+
function convertSettingsToSnakeCase(settings) {
|
|
15
|
+
return _.mapKeys(settings, (value, key) => _.snakeCase(key));
|
|
22
16
|
}
|
|
23
17
|
|
|
24
18
|
function getAdditionalHeadersFromSettings(settings) {
|
|
25
|
-
return
|
|
19
|
+
return convertSettingsToSnakeCase(settings.additionalVars);
|
|
26
20
|
}
|
|
27
21
|
|
|
28
22
|
class Sailor {
|
|
@@ -32,50 +26,35 @@ class Sailor {
|
|
|
32
26
|
constructor(settings) {
|
|
33
27
|
this.settings = settings;
|
|
34
28
|
this.messagesCount = 0;
|
|
35
|
-
this.
|
|
29
|
+
this.proxyClient = new ProxyClient(settings);
|
|
36
30
|
this.componentReader = new ComponentReader();
|
|
37
31
|
this.snapshot = {};
|
|
38
32
|
this.stepData = {};
|
|
39
33
|
this.shutdownCallback = null;
|
|
34
|
+
// TODO move endpoint to proxy
|
|
40
35
|
//eslint-disable-next-line new-cap
|
|
41
36
|
this.apiClient = RestApiClient(
|
|
42
37
|
settings.API_USERNAME,
|
|
38
|
+
// TODO find a way to make username and key consistent (without running api tests and looking up
|
|
39
|
+
// correct values in MongoDB)
|
|
43
40
|
settings.API_KEY,
|
|
44
41
|
{
|
|
45
42
|
retryCount: settings.API_REQUEST_RETRY_ATTEMPTS,
|
|
46
43
|
retryDelay: settings.API_REQUEST_RETRY_DELAY
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
const objectStorage = new ObjectStorage({
|
|
50
|
-
uri: settings.OBJECT_STORAGE_URI,
|
|
51
|
-
jwtSecret: settings.OBJECT_STORAGE_TOKEN
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
const encryptor = new Encryptor(settings.MESSAGE_CRYPTO_PASSWORD, settings.MESSAGE_CRYPTO_IV);
|
|
55
|
-
this.objectStorage = objectStorage.use(
|
|
56
|
-
() => encryptor.createCipher(),
|
|
57
|
-
() => encryptor.createDecipher()
|
|
44
|
+
}
|
|
58
45
|
);
|
|
59
|
-
|
|
60
|
-
this.throttles = {
|
|
61
|
-
// 100 Messages per Second
|
|
62
|
-
data: pThrottle(() => Promise.resolve(true),
|
|
63
|
-
settings.DATA_RATE_LIMIT,
|
|
64
|
-
settings.RATE_INTERVAL),
|
|
65
|
-
error: pThrottle(() => Promise.resolve(true),
|
|
66
|
-
settings.ERROR_RATE_LIMIT,
|
|
67
|
-
settings.RATE_INTERVAL),
|
|
68
|
-
snapshot: pThrottle(() => Promise.resolve(true),
|
|
69
|
-
settings.SNAPSHOT_RATE_LIMIT,
|
|
70
|
-
settings.RATE_INTERVAL)
|
|
71
|
-
};
|
|
72
46
|
}
|
|
73
47
|
|
|
74
48
|
async connect() {
|
|
75
|
-
return this.
|
|
49
|
+
return this.proxyClient.connect();
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
async isConnected() {
|
|
53
|
+
return this.proxyClient.isConnected();
|
|
76
54
|
}
|
|
77
55
|
|
|
78
56
|
async prepare() {
|
|
57
|
+
log.trace('prepare sailor');
|
|
79
58
|
const {
|
|
80
59
|
settings: {
|
|
81
60
|
COMPONENT_PATH: compPath,
|
|
@@ -101,11 +80,12 @@ class Sailor {
|
|
|
101
80
|
}
|
|
102
81
|
|
|
103
82
|
async disconnect() {
|
|
83
|
+
// TODO: delete if not needed (currently used only in old tests)
|
|
104
84
|
log.debug('Disconnecting, %s messages in processing', this.messagesCount);
|
|
105
|
-
return this.
|
|
85
|
+
return this.proxyClient.disconnect();
|
|
106
86
|
}
|
|
107
87
|
|
|
108
|
-
|
|
88
|
+
reportError(err) {
|
|
109
89
|
const headers = Object.assign({}, getAdditionalHeadersFromSettings(this.settings), {
|
|
110
90
|
execId: this.settings.EXEC_ID,
|
|
111
91
|
taskId: this.settings.FLOW_ID,
|
|
@@ -116,7 +96,7 @@ class Sailor {
|
|
|
116
96
|
compId: this.settings.COMP_ID,
|
|
117
97
|
function: this.settings.FUNCTION
|
|
118
98
|
});
|
|
119
|
-
return this.
|
|
99
|
+
return this.proxyClient.sendError(err, headers);
|
|
120
100
|
}
|
|
121
101
|
|
|
122
102
|
startup() {
|
|
@@ -184,17 +164,16 @@ class Sailor {
|
|
|
184
164
|
}
|
|
185
165
|
|
|
186
166
|
run() {
|
|
187
|
-
const incomingQueue = this.settings.LISTEN_MESSAGES_ON;
|
|
188
167
|
const handler = this.processMessageAndMaybeShutdownCallback.bind(this);
|
|
189
|
-
log.debug('Start listening for messages
|
|
190
|
-
return this.
|
|
168
|
+
log.debug('Start listening for messages');
|
|
169
|
+
return this.proxyClient.listenForMessages(handler);
|
|
191
170
|
}
|
|
192
171
|
|
|
193
|
-
async processMessageAndMaybeShutdownCallback(
|
|
172
|
+
async processMessageAndMaybeShutdownCallback(headers, body) {
|
|
194
173
|
try {
|
|
195
|
-
return await this.processMessage(
|
|
174
|
+
return await this.processMessage(headers, body);
|
|
196
175
|
} catch (e) {
|
|
197
|
-
log.error('Something very bad happened during message processing');
|
|
176
|
+
log.error(e, 'Something very bad happened during message processing');
|
|
198
177
|
} finally {
|
|
199
178
|
if (this.shutdownCallback) {
|
|
200
179
|
if (this.messagesCount === 0) {
|
|
@@ -216,7 +195,7 @@ class Sailor {
|
|
|
216
195
|
return new Promise(resolve => this.shutdownCallback = resolve);
|
|
217
196
|
}
|
|
218
197
|
|
|
219
|
-
await this.
|
|
198
|
+
await this.proxyClient.disconnect();
|
|
220
199
|
if (this.messagesCount === 0) {
|
|
221
200
|
// there is no unfinished processMessage invocation, let's just resolve scheduleShutdown now
|
|
222
201
|
log.debug('scheduleShutdown – about to shutdown immediately');
|
|
@@ -228,103 +207,23 @@ class Sailor {
|
|
|
228
207
|
return new Promise(resolve => this.shutdownCallback = resolve);
|
|
229
208
|
}
|
|
230
209
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
const { headers } = message.properties;
|
|
234
|
-
|
|
235
|
-
// Get meta headers
|
|
236
|
-
const metaHeaderNames = Object.keys(headers)
|
|
237
|
-
.filter(key => key.toLowerCase().startsWith(AMQP_HEADER_META_PREFIX));
|
|
238
|
-
|
|
239
|
-
const metaHeaders = _.pick(headers, metaHeaderNames);
|
|
240
|
-
const metaHeadersLowerCased = _.mapKeys(metaHeaders, (value, key) => key.toLowerCase());
|
|
241
|
-
|
|
242
|
-
const result = {
|
|
243
|
-
stepId: headers.stepId, // the only use is passthrough mechanism
|
|
244
|
-
...metaHeadersLowerCased,
|
|
245
|
-
threadId: headers.threadId || metaHeadersLowerCased['x-eio-meta-trace-id'],
|
|
246
|
-
messageId: headers.messageId,
|
|
247
|
-
parentMessageId: headers.parentMessageId
|
|
248
|
-
};
|
|
249
|
-
if (!result.threadId) {
|
|
250
|
-
const threadId = uuid.v4();
|
|
251
|
-
log.debug({ threadId }, 'Initiate new thread as it is not started ATM');
|
|
252
|
-
result.threadId = threadId;
|
|
253
|
-
}
|
|
254
|
-
if (headers.reply_to) {
|
|
255
|
-
result.reply_to = headers.reply_to;
|
|
256
|
-
}
|
|
257
|
-
return result;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
async fetchMessageBody(message, logger) {
|
|
261
|
-
const { body, headers } = message;
|
|
262
|
-
|
|
263
|
-
logger.info('Checking if incoming messages is lightweight...');
|
|
264
|
-
|
|
265
|
-
if (!headers) {
|
|
266
|
-
logger.info('Empty headers so not lightweight.');
|
|
267
|
-
return body;
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
const { [OBJECT_ID_HEADER]: objectId } = headers;
|
|
271
|
-
|
|
272
|
-
if (!objectId) {
|
|
273
|
-
logger.trace('No object id header so not lightweight.');
|
|
274
|
-
return body;
|
|
275
|
-
}
|
|
276
|
-
|
|
277
|
-
logger.info('Object id header found, message is lightweight.', { objectId });
|
|
278
|
-
|
|
279
|
-
let object;
|
|
280
|
-
|
|
281
|
-
logger.info('Going to fetch message body.', { objectId });
|
|
282
|
-
|
|
283
|
-
try {
|
|
284
|
-
object = await this.objectStorage.getOne(
|
|
285
|
-
objectId,
|
|
286
|
-
{ jwtPayloadOrToken: this.settings.OBJECT_STORAGE_TOKEN }
|
|
287
|
-
);
|
|
288
|
-
} catch (e) {
|
|
289
|
-
log.error(e);
|
|
290
|
-
throw new Error(`Failed to get message body with id=${objectId}`);
|
|
291
|
-
}
|
|
292
|
-
|
|
293
|
-
logger.info('Successfully obtained message body.', { objectId });
|
|
294
|
-
logger.trace('Message body object received');
|
|
295
|
-
|
|
296
|
-
return object.data;
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
uploadMessageBody(bodyBuf) {
|
|
300
|
-
const stream = () => Readable.from(bodyBuf);
|
|
301
|
-
return this.objectStorage.add(
|
|
302
|
-
stream,
|
|
303
|
-
{ jwtPayloadOrToken: this.settings.OBJECT_STORAGE_TOKEN }
|
|
304
|
-
);
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
async runExec(module, payload, message, outgoingMessageHeaders, stepData, timeStart, logger) {
|
|
210
|
+
async runExec(module, payload, incomingMessageHeaders, outgoingMessageHeaders, stepData, timeStart, logger) {
|
|
211
|
+
log.debug({ incomingMessageHeaders }, 'runExec started');
|
|
308
212
|
const origPassthrough = _.cloneDeep(payload.passthrough) || {};
|
|
309
|
-
const incomingMessageHeaders = this.readIncomingMessageHeaders(message);
|
|
310
|
-
const messageId = incomingMessageHeaders.messageId;
|
|
311
213
|
const settings = this.settings;
|
|
312
214
|
const cfg = _.cloneDeep(stepData.config) || {};
|
|
313
215
|
const snapshot = _.cloneDeep(this.snapshot);
|
|
314
|
-
const { deliveryTag } = message.fields;
|
|
315
216
|
|
|
316
217
|
const that = this;
|
|
317
218
|
|
|
318
219
|
await new Promise(resolve => {
|
|
319
220
|
let endWasEmitted;
|
|
320
221
|
|
|
321
|
-
|
|
322
222
|
const taskExec = new TaskExec({
|
|
323
223
|
loggerOptions: _.pick(incomingMessageHeaders, ['threadId', 'messageId', 'parentMessageId']),
|
|
324
224
|
variables: stepData.variables,
|
|
325
225
|
services: {
|
|
326
226
|
apiClient: this.apiClient,
|
|
327
|
-
amqp: this.amqpConnection,
|
|
328
227
|
config: this.settings
|
|
329
228
|
}
|
|
330
229
|
});
|
|
@@ -391,34 +290,18 @@ class Sailor {
|
|
|
391
290
|
let passthroughIds;
|
|
392
291
|
try {
|
|
393
292
|
[bodyId, ...passthroughIds] = await Promise.all([
|
|
394
|
-
that.uploadMessageBody(bodyBuf),
|
|
293
|
+
that.proxyClient.uploadMessageBody(bodyBuf),
|
|
395
294
|
...passthroughBufs.map(async ({ stepId, body, id }) => {
|
|
396
|
-
const
|
|
397
|
-
return { stepId, bodyId
|
|
295
|
+
const bodyId = id || await that.proxyClient.uploadMessageBody(body);
|
|
296
|
+
return { stepId, bodyId };
|
|
398
297
|
})
|
|
399
298
|
]);
|
|
400
299
|
} catch (e) {
|
|
401
|
-
logger.error(
|
|
402
|
-
|
|
403
|
-
errName: e && e.name,
|
|
404
|
-
errMessage: e && e.message,
|
|
405
|
-
errCode: e && e.code,
|
|
406
|
-
bodySize: bodyBuf.length,
|
|
407
|
-
passthroughCount: passthroughBufs.length,
|
|
408
|
-
passthroughInfo: passthroughBufs.map(({ stepId, id }) => ({
|
|
409
|
-
stepId,
|
|
410
|
-
hasExistingId: Boolean(id)
|
|
411
|
-
}))
|
|
412
|
-
},
|
|
413
|
-
'Error during message/passthrough body upload'
|
|
414
|
-
);
|
|
415
|
-
const details = e && e.message ? `: ${e.message}` : '';
|
|
416
|
-
return onError(
|
|
417
|
-
new Error(`Lightweight message/passthrough body upload error${details}`)
|
|
418
|
-
);
|
|
300
|
+
logger.error(e, 'Error during message/passthrough body upload');
|
|
301
|
+
return onError(new Error('Lightweight message/passthrough body upload error'));
|
|
419
302
|
}
|
|
420
303
|
|
|
421
|
-
logger.info(
|
|
304
|
+
logger.info({ id: bodyId }, 'Message body uploaded');
|
|
422
305
|
const { headers } = data;
|
|
423
306
|
data.body = {};
|
|
424
307
|
data.headers = {
|
|
@@ -455,7 +338,7 @@ class Sailor {
|
|
|
455
338
|
logger.trace('Body is not empty.', { stepId });
|
|
456
339
|
return;
|
|
457
340
|
}
|
|
458
|
-
data.passthrough[stepId].body = await that.fetchMessageBody(
|
|
341
|
+
data.passthrough[stepId].body = await that.proxyClient.fetchMessageBody(
|
|
459
342
|
passthrough[stepId],
|
|
460
343
|
logger
|
|
461
344
|
);
|
|
@@ -474,7 +357,12 @@ class Sailor {
|
|
|
474
357
|
log.trace('Going to send outgoing message');
|
|
475
358
|
|
|
476
359
|
try {
|
|
477
|
-
await that.
|
|
360
|
+
await that.proxyClient.sendMessage({
|
|
361
|
+
incomingMessageId: incomingMessageHeaders.messageId,
|
|
362
|
+
data,
|
|
363
|
+
headers,
|
|
364
|
+
type: 'data'
|
|
365
|
+
});
|
|
478
366
|
log.trace('Outgoing message sent');
|
|
479
367
|
} catch (err) {
|
|
480
368
|
return onError(err);
|
|
@@ -487,7 +375,12 @@ class Sailor {
|
|
|
487
375
|
messageProcessingTime: Date.now() - timeStart
|
|
488
376
|
}, 'processMessage emit HttpReply');
|
|
489
377
|
|
|
490
|
-
return that.
|
|
378
|
+
return that.proxyClient.sendMessage({
|
|
379
|
+
incomingMessageId: incomingMessageHeaders.messageId,
|
|
380
|
+
data: reply,
|
|
381
|
+
headers,
|
|
382
|
+
type: 'http-reply'
|
|
383
|
+
});
|
|
491
384
|
}
|
|
492
385
|
|
|
493
386
|
async function onError(err) {
|
|
@@ -500,7 +393,7 @@ class Sailor {
|
|
|
500
393
|
messageProcessingTime: Date.now() - timeStart
|
|
501
394
|
}, 'processMessage emit error');
|
|
502
395
|
headers.end = new Date().getTime();
|
|
503
|
-
return that.
|
|
396
|
+
return that.proxyClient.sendError(err, headers, payload, incomingMessageHeaders);
|
|
504
397
|
}
|
|
505
398
|
|
|
506
399
|
async function onRebound(err) {
|
|
@@ -511,14 +404,14 @@ class Sailor {
|
|
|
511
404
|
messagesCount: that.messagesCount,
|
|
512
405
|
messageProcessingTime: Date.now() - timeStart
|
|
513
406
|
}, 'processMessage emit rebound');
|
|
514
|
-
return that.
|
|
407
|
+
return that.proxyClient.sendRebound(err, incomingMessageHeaders, outgoingHeaders);
|
|
515
408
|
}
|
|
516
409
|
|
|
517
410
|
async function onSnapshot(data) {
|
|
518
411
|
const headers = _.clone(outgoingMessageHeaders);
|
|
519
412
|
headers.snapshotEvent = 'snapshot';
|
|
520
413
|
that.snapshot = data; //replacing `local` snapshot
|
|
521
|
-
return that.
|
|
414
|
+
return that.proxyClient.sendSnapshot(data, headers);
|
|
522
415
|
}
|
|
523
416
|
|
|
524
417
|
async function onUpdateSnapshot(data) {
|
|
@@ -530,7 +423,7 @@ class Sailor {
|
|
|
530
423
|
return log.warn('ERROR: $set is not supported any more in `updateSnapshot` event');
|
|
531
424
|
}
|
|
532
425
|
_.extend(that.snapshot, data); //updating `local` snapshot
|
|
533
|
-
return that.
|
|
426
|
+
return that.proxyClient.sendSnapshot(data, headers);
|
|
534
427
|
} else {
|
|
535
428
|
log.error('You should pass an object to the `updateSnapshot` event');
|
|
536
429
|
}
|
|
@@ -543,14 +436,14 @@ class Sailor {
|
|
|
543
436
|
|
|
544
437
|
try {
|
|
545
438
|
await that.apiClient.accounts.update(cfg._account, { keys: keys });
|
|
546
|
-
logger.debug('Successfully updated keys
|
|
439
|
+
logger.debug({ messageId: incomingMessageHeaders.messageId }, 'Successfully updated keys');
|
|
547
440
|
} catch (error) {
|
|
548
|
-
logger.
|
|
441
|
+
logger.debug({ messageId: incomingMessageHeaders.messageId }, 'Failed to update keys');
|
|
549
442
|
await onError(error);
|
|
550
443
|
}
|
|
551
444
|
}
|
|
552
445
|
|
|
553
|
-
|
|
446
|
+
function onEnd() {
|
|
554
447
|
if (endWasEmitted) {
|
|
555
448
|
logger.warn({
|
|
556
449
|
messagesCount: that.messagesCount,
|
|
@@ -562,11 +455,12 @@ class Sailor {
|
|
|
562
455
|
|
|
563
456
|
endWasEmitted = true;
|
|
564
457
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
458
|
+
that.proxyClient.finishProcessing(
|
|
459
|
+
incomingMessageHeaders,
|
|
460
|
+
taskExec.errorCount > 0
|
|
461
|
+
? MESSAGE_PROCESSING_STATUS.ERROR
|
|
462
|
+
: MESSAGE_PROCESSING_STATUS.SUCCESS
|
|
463
|
+
);
|
|
570
464
|
that.messagesCount -= 1;
|
|
571
465
|
logger.trace({
|
|
572
466
|
messagesCount: that.messagesCount,
|
|
@@ -595,43 +489,21 @@ class Sailor {
|
|
|
595
489
|
}
|
|
596
490
|
}
|
|
597
491
|
|
|
598
|
-
async processMessage(
|
|
492
|
+
async processMessage(headers, payload) {
|
|
599
493
|
//eslint-disable-next-line consistent-this
|
|
600
494
|
const self = this;
|
|
601
495
|
const settings = this.settings;
|
|
602
|
-
const incomingMessageHeaders = this.readIncomingMessageHeaders(message);
|
|
603
496
|
|
|
604
497
|
self.messagesCount += 1;
|
|
605
498
|
|
|
606
499
|
const timeStart = Date.now();
|
|
607
500
|
|
|
608
|
-
const messageId = incomingMessageHeaders.messageId;
|
|
609
501
|
const logger = log.child({
|
|
610
|
-
threadId:
|
|
611
|
-
messageId: messageId || 'unknown',
|
|
612
|
-
parentMessageId:
|
|
613
|
-
...message.fields
|
|
502
|
+
threadId: headers.threadId || 'unknown',
|
|
503
|
+
messageId: headers.messageId || 'unknown',
|
|
504
|
+
parentMessageId: headers.parentMessageId || 'unknown'
|
|
614
505
|
});
|
|
615
506
|
|
|
616
|
-
if (messageId) {
|
|
617
|
-
const alreadyExists = messagesDB.getMessageById(messageId);
|
|
618
|
-
// Add message to DB even if it already exists
|
|
619
|
-
messagesDB.addMessage(messageId, message);
|
|
620
|
-
if (alreadyExists) {
|
|
621
|
-
logger.warn({ messageId }, 'Duplicate message detected. This'
|
|
622
|
-
+ ' delivery will be ignored; the handler that first received'
|
|
623
|
-
+ ' this message will process it as part of deduplication.');
|
|
624
|
-
// If message was in messagesDB, it means that the connection was closed
|
|
625
|
-
// and this message was redelivered. In this case, the process for original
|
|
626
|
-
// message is waiting for this message to be added to DB and then ack or
|
|
627
|
-
// nack the new message, instead of the one that was delivered by closed
|
|
628
|
-
// channel
|
|
629
|
-
return;
|
|
630
|
-
}
|
|
631
|
-
} else {
|
|
632
|
-
logger.warn('Message does not have messageId');
|
|
633
|
-
}
|
|
634
|
-
|
|
635
507
|
logger.trace({ messagesCount: this.messagesCount }, 'processMessage received');
|
|
636
508
|
|
|
637
509
|
const stepData = this.stepData;
|
|
@@ -639,10 +511,10 @@ class Sailor {
|
|
|
639
511
|
log.debug('Trigger or action: %s', settings.FUNCTION);
|
|
640
512
|
const outgoingMessageId = uuid.v4();
|
|
641
513
|
const outgoingMessageHeaders = {
|
|
642
|
-
...
|
|
514
|
+
...headers,
|
|
643
515
|
...getAdditionalHeadersFromSettings(settings),
|
|
644
|
-
parentMessageId:
|
|
645
|
-
threadId:
|
|
516
|
+
parentMessageId: headers.messageId,
|
|
517
|
+
threadId: headers.threadId,
|
|
646
518
|
messageId: outgoingMessageId,
|
|
647
519
|
execId: settings.EXEC_ID,
|
|
648
520
|
taskId: settings.FLOW_ID,
|
|
@@ -660,10 +532,8 @@ class Sailor {
|
|
|
660
532
|
} catch (e) {
|
|
661
533
|
log.error(e);
|
|
662
534
|
outgoingMessageHeaders.end = new Date().getTime();
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
self.amqpConnection.reject(messageId)
|
|
666
|
-
]);
|
|
535
|
+
self.proxyClient.sendError(e, outgoingMessageHeaders, payload, headers);
|
|
536
|
+
self.proxyClient.finishProcessing(headers, MESSAGE_PROCESSING_STATUS.ERROR);
|
|
667
537
|
return;
|
|
668
538
|
}
|
|
669
539
|
|
|
@@ -676,12 +546,12 @@ class Sailor {
|
|
|
676
546
|
await Promise.all([
|
|
677
547
|
(async () => {
|
|
678
548
|
logger.trace('Going to check if incoming message body is lightweight.');
|
|
679
|
-
payload.body = await this.fetchMessageBody(payload, logger);
|
|
549
|
+
payload.body = await this.proxyClient.fetchMessageBody(payload, logger);
|
|
680
550
|
})(),
|
|
681
551
|
...(passthrough
|
|
682
552
|
? Object.keys(passthrough).map(async stepId => {
|
|
683
553
|
logger.trace('Going to check if passthrough for step is lightweight.', { stepId });
|
|
684
|
-
payload.passthrough[stepId].body = await this.fetchMessageBody(
|
|
554
|
+
payload.passthrough[stepId].body = await this.proxyClient.fetchMessageBody(
|
|
685
555
|
payload.passthrough[stepId],
|
|
686
556
|
logger
|
|
687
557
|
);
|
|
@@ -691,15 +561,13 @@ class Sailor {
|
|
|
691
561
|
} catch (e) {
|
|
692
562
|
logger.error(e);
|
|
693
563
|
outgoingMessageHeaders.end = new Date().getTime();
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
self.amqpConnection.reject(messageId)
|
|
697
|
-
]);
|
|
564
|
+
self.proxyClient.sendError(e, outgoingMessageHeaders, payload, headers);
|
|
565
|
+
self.proxyClient.finishProcessing(headers, MESSAGE_PROCESSING_STATUS.ERROR);
|
|
698
566
|
return;
|
|
699
567
|
}
|
|
700
568
|
}
|
|
701
569
|
|
|
702
|
-
await this.runExec(module, payload,
|
|
570
|
+
await this.runExec(module, payload, headers, outgoingMessageHeaders, stepData, timeStart, logger);
|
|
703
571
|
}
|
|
704
572
|
}
|
|
705
573
|
|
package/lib/settings.js
CHANGED
|
@@ -4,14 +4,22 @@ const PREFIX = 'ELASTICIO_';
|
|
|
4
4
|
|
|
5
5
|
function getOptionalEnvVars(envVars) {
|
|
6
6
|
const optional = {
|
|
7
|
-
REBOUND_INITIAL_EXPIRATION: 15000,
|
|
8
|
-
REBOUND_LIMIT: 20,
|
|
9
7
|
COMPONENT_PATH: '',
|
|
10
|
-
|
|
8
|
+
PROXY_PREFETCH_SAILOR: 1,
|
|
11
9
|
STARTUP_REQUIRED: false,
|
|
12
10
|
HOOK_SHUTDOWN: false,
|
|
13
11
|
API_REQUEST_RETRY_ATTEMPTS: 3,
|
|
14
12
|
API_REQUEST_RETRY_DELAY: 100,
|
|
13
|
+
PROXY_RECONNECT_MAX_RETRIES: Infinity,
|
|
14
|
+
PROXY_RECONNECT_INITIAL_DELAY: 1000,
|
|
15
|
+
PROXY_RECONNECT_MAX_DELAY: 30 * 1000, // 30 seconds
|
|
16
|
+
PROXY_RECONNECT_BACKOFF_MULTIPLIER: 2,
|
|
17
|
+
PROXY_RECONNECT_JITTER_FACTOR: 0.3,
|
|
18
|
+
PROXY_OBJECT_REQUEST_RETRY_ATTEMPTS: Infinity,
|
|
19
|
+
PROXY_OBJECT_REQUEST_RETRY_DELAY: 100,
|
|
20
|
+
PROXY_OBJECT_REQUEST_MAX_RETRY_DELAY: 5 * 60 * 1000, // 5 mins
|
|
21
|
+
|
|
22
|
+
// TODO: Move to proxy?
|
|
15
23
|
DATA_RATE_LIMIT: 10, // 10 data events every 100ms
|
|
16
24
|
ERROR_RATE_LIMIT: 2, // 2 errors every 100ms
|
|
17
25
|
SNAPSHOT_RATE_LIMIT: 2, // 2 Snapshots every 100ms
|
|
@@ -20,19 +28,15 @@ function getOptionalEnvVars(envVars) {
|
|
|
20
28
|
AMQP_PUBLISH_RETRY_DELAY: 100, // 100ms
|
|
21
29
|
AMQP_PUBLISH_RETRY_ATTEMPTS: Infinity,
|
|
22
30
|
AMQP_PUBLISH_MAX_RETRY_DELAY: 5 * 60 * 1000, // 5 mins
|
|
31
|
+
// Should be defaulted to true and moved to proxy
|
|
23
32
|
AMQP_PERSISTENT_MESSAGES: false,
|
|
33
|
+
|
|
34
|
+
OBJECT_STORAGE_SIZE_THRESHOLD: 1048576,
|
|
24
35
|
OUTGOING_MESSAGE_SIZE_LIMIT: 10485760,
|
|
25
36
|
NO_SELF_PASSTRHOUGH: false,
|
|
26
37
|
PROTOCOL_VERSION: 1,
|
|
27
|
-
NO_ERROR_REPLIES: false,
|
|
28
38
|
INPUT_FORMAT: 'default',
|
|
29
|
-
OBJECT_STORAGE_URI: null,
|
|
30
|
-
OBJECT_STORAGE_TOKEN: null,
|
|
31
|
-
OBJECT_STORAGE_SIZE_THRESHOLD: 1048576,
|
|
32
39
|
EMIT_LIGHTWEIGHT_MESSAGE: false,
|
|
33
|
-
AMQP_RECONNECT_ATTEMPTS: 3,
|
|
34
|
-
AMQP_RECONNECT_TIMEOUT: 100,
|
|
35
|
-
WAIT_MESSAGES_TIMEOUT: 50
|
|
36
40
|
};
|
|
37
41
|
|
|
38
42
|
const result = {};
|
|
@@ -87,16 +91,9 @@ function getMandatoryEnvVars(envVars) {
|
|
|
87
91
|
];
|
|
88
92
|
|
|
89
93
|
const requiredForMessageProcessing = [
|
|
90
|
-
'
|
|
91
|
-
'
|
|
92
|
-
'
|
|
93
|
-
|
|
94
|
-
'DATA_ROUTING_KEY',
|
|
95
|
-
'ERROR_ROUTING_KEY',
|
|
96
|
-
'REBOUND_ROUTING_KEY',
|
|
97
|
-
'SNAPSHOT_ROUTING_KEY',
|
|
98
|
-
'MESSAGE_CRYPTO_IV',
|
|
99
|
-
'MESSAGE_CRYPTO_PASSWORD'
|
|
94
|
+
'SAILOR_PROXY_URI',
|
|
95
|
+
'MESSAGE_CRYPTO_PASSWORD',
|
|
96
|
+
'MESSAGE_CRYPTO_IV'
|
|
100
97
|
];
|
|
101
98
|
|
|
102
99
|
const envVarsList = requiredAlways.slice(0);
|
package/lib/utils.js
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
function getJitteredDelay(baseDelay, jitterFactor) {
|
|
2
|
+
const minJitter = baseDelay * -jitterFactor;
|
|
3
|
+
const maxJitter = baseDelay * jitterFactor;
|
|
4
|
+
const jitter = Math.random() * (maxJitter - minJitter) + minJitter;
|
|
5
|
+
return baseDelay + jitter;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
module.exports.getJitteredDelay = getJitteredDelay;
|
package/mise.toml
ADDED
package/package.json
CHANGED
|
@@ -1,23 +1,23 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "elasticio-sailor-nodejs",
|
|
3
3
|
"description": "The official elastic.io library for bootstrapping and executing for Node.js connectors",
|
|
4
|
-
"version": "3.0.0-
|
|
4
|
+
"version": "3.0.0-sailor-proxy-dev1",
|
|
5
5
|
"main": "run.js",
|
|
6
6
|
"scripts": {
|
|
7
|
+
"build": "tsc",
|
|
7
8
|
"audit": "better-npm-audit audit --level high --production",
|
|
8
|
-
"lint": "./node_modules/.bin/eslint lib spec mocha_spec lib run.js runService.js",
|
|
9
9
|
"pretest": "npm run lint",
|
|
10
|
+
"lint": "eslint --ext .ts .",
|
|
10
11
|
"test": "npm run test:jasmine && npm run test:mocha",
|
|
11
12
|
"test:jasmine": "NODE_ENV=test jasmine-node spec",
|
|
12
13
|
"test:mocha": "NODE_ENV=test node_modules/.bin/mocha --recursive mocha_spec",
|
|
13
|
-
"postpublish": "./postpublish.js"
|
|
14
|
+
"postpublish": "./postpublish.js",
|
|
15
|
+
"dev:local": "node run.local.js | bunyan"
|
|
14
16
|
},
|
|
15
17
|
"engines": {
|
|
16
18
|
"node": ">=12.13.0"
|
|
17
19
|
},
|
|
18
20
|
"dependencies": {
|
|
19
|
-
"@elastic.io/maester-client": "6.0.0",
|
|
20
|
-
"amqplib": "0.8.0",
|
|
21
21
|
"bunyan": "1.8.10",
|
|
22
22
|
"co": "4.6.0",
|
|
23
23
|
"debug": "3.1.0",
|
|
@@ -45,7 +45,9 @@
|
|
|
45
45
|
"request": "2.88.0",
|
|
46
46
|
"request-promise-native": "1.0.5",
|
|
47
47
|
"sinon": "9.0.2",
|
|
48
|
-
"sinon-chai": "3.5.0"
|
|
48
|
+
"sinon-chai": "3.5.0",
|
|
49
|
+
"ts-node": "10.4.0",
|
|
50
|
+
"typescript": "4.4.4"
|
|
49
51
|
},
|
|
50
52
|
"repository": "elasticio/sailor-nodejs",
|
|
51
53
|
"license": "Apache-2.0"
|