elasticio-sailor-nodejs 3.0.0-dev7 → 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 +70 -186
- 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,9 +290,9 @@ 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 bodyId = id || await that.uploadMessageBody(body);
|
|
295
|
+
const bodyId = id || await that.proxyClient.uploadMessageBody(body);
|
|
397
296
|
return { stepId, bodyId };
|
|
398
297
|
})
|
|
399
298
|
]);
|
|
@@ -402,7 +301,7 @@ class Sailor {
|
|
|
402
301
|
return onError(new Error('Lightweight message/passthrough body upload error'));
|
|
403
302
|
}
|
|
404
303
|
|
|
405
|
-
logger.info(
|
|
304
|
+
logger.info({ id: bodyId }, 'Message body uploaded');
|
|
406
305
|
const { headers } = data;
|
|
407
306
|
data.body = {};
|
|
408
307
|
data.headers = {
|
|
@@ -439,7 +338,7 @@ class Sailor {
|
|
|
439
338
|
logger.trace('Body is not empty.', { stepId });
|
|
440
339
|
return;
|
|
441
340
|
}
|
|
442
|
-
data.passthrough[stepId].body = await that.fetchMessageBody(
|
|
341
|
+
data.passthrough[stepId].body = await that.proxyClient.fetchMessageBody(
|
|
443
342
|
passthrough[stepId],
|
|
444
343
|
logger
|
|
445
344
|
);
|
|
@@ -458,7 +357,12 @@ class Sailor {
|
|
|
458
357
|
log.trace('Going to send outgoing message');
|
|
459
358
|
|
|
460
359
|
try {
|
|
461
|
-
await that.
|
|
360
|
+
await that.proxyClient.sendMessage({
|
|
361
|
+
incomingMessageId: incomingMessageHeaders.messageId,
|
|
362
|
+
data,
|
|
363
|
+
headers,
|
|
364
|
+
type: 'data'
|
|
365
|
+
});
|
|
462
366
|
log.trace('Outgoing message sent');
|
|
463
367
|
} catch (err) {
|
|
464
368
|
return onError(err);
|
|
@@ -471,7 +375,12 @@ class Sailor {
|
|
|
471
375
|
messageProcessingTime: Date.now() - timeStart
|
|
472
376
|
}, 'processMessage emit HttpReply');
|
|
473
377
|
|
|
474
|
-
return that.
|
|
378
|
+
return that.proxyClient.sendMessage({
|
|
379
|
+
incomingMessageId: incomingMessageHeaders.messageId,
|
|
380
|
+
data: reply,
|
|
381
|
+
headers,
|
|
382
|
+
type: 'http-reply'
|
|
383
|
+
});
|
|
475
384
|
}
|
|
476
385
|
|
|
477
386
|
async function onError(err) {
|
|
@@ -484,7 +393,7 @@ class Sailor {
|
|
|
484
393
|
messageProcessingTime: Date.now() - timeStart
|
|
485
394
|
}, 'processMessage emit error');
|
|
486
395
|
headers.end = new Date().getTime();
|
|
487
|
-
return that.
|
|
396
|
+
return that.proxyClient.sendError(err, headers, payload, incomingMessageHeaders);
|
|
488
397
|
}
|
|
489
398
|
|
|
490
399
|
async function onRebound(err) {
|
|
@@ -495,14 +404,14 @@ class Sailor {
|
|
|
495
404
|
messagesCount: that.messagesCount,
|
|
496
405
|
messageProcessingTime: Date.now() - timeStart
|
|
497
406
|
}, 'processMessage emit rebound');
|
|
498
|
-
return that.
|
|
407
|
+
return that.proxyClient.sendRebound(err, incomingMessageHeaders, outgoingHeaders);
|
|
499
408
|
}
|
|
500
409
|
|
|
501
410
|
async function onSnapshot(data) {
|
|
502
411
|
const headers = _.clone(outgoingMessageHeaders);
|
|
503
412
|
headers.snapshotEvent = 'snapshot';
|
|
504
413
|
that.snapshot = data; //replacing `local` snapshot
|
|
505
|
-
return that.
|
|
414
|
+
return that.proxyClient.sendSnapshot(data, headers);
|
|
506
415
|
}
|
|
507
416
|
|
|
508
417
|
async function onUpdateSnapshot(data) {
|
|
@@ -514,7 +423,7 @@ class Sailor {
|
|
|
514
423
|
return log.warn('ERROR: $set is not supported any more in `updateSnapshot` event');
|
|
515
424
|
}
|
|
516
425
|
_.extend(that.snapshot, data); //updating `local` snapshot
|
|
517
|
-
return that.
|
|
426
|
+
return that.proxyClient.sendSnapshot(data, headers);
|
|
518
427
|
} else {
|
|
519
428
|
log.error('You should pass an object to the `updateSnapshot` event');
|
|
520
429
|
}
|
|
@@ -527,14 +436,14 @@ class Sailor {
|
|
|
527
436
|
|
|
528
437
|
try {
|
|
529
438
|
await that.apiClient.accounts.update(cfg._account, { keys: keys });
|
|
530
|
-
logger.debug('Successfully updated keys
|
|
439
|
+
logger.debug({ messageId: incomingMessageHeaders.messageId }, 'Successfully updated keys');
|
|
531
440
|
} catch (error) {
|
|
532
|
-
logger.
|
|
441
|
+
logger.debug({ messageId: incomingMessageHeaders.messageId }, 'Failed to update keys');
|
|
533
442
|
await onError(error);
|
|
534
443
|
}
|
|
535
444
|
}
|
|
536
445
|
|
|
537
|
-
|
|
446
|
+
function onEnd() {
|
|
538
447
|
if (endWasEmitted) {
|
|
539
448
|
logger.warn({
|
|
540
449
|
messagesCount: that.messagesCount,
|
|
@@ -546,11 +455,12 @@ class Sailor {
|
|
|
546
455
|
|
|
547
456
|
endWasEmitted = true;
|
|
548
457
|
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
458
|
+
that.proxyClient.finishProcessing(
|
|
459
|
+
incomingMessageHeaders,
|
|
460
|
+
taskExec.errorCount > 0
|
|
461
|
+
? MESSAGE_PROCESSING_STATUS.ERROR
|
|
462
|
+
: MESSAGE_PROCESSING_STATUS.SUCCESS
|
|
463
|
+
);
|
|
554
464
|
that.messagesCount -= 1;
|
|
555
465
|
logger.trace({
|
|
556
466
|
messagesCount: that.messagesCount,
|
|
@@ -579,43 +489,21 @@ class Sailor {
|
|
|
579
489
|
}
|
|
580
490
|
}
|
|
581
491
|
|
|
582
|
-
async processMessage(
|
|
492
|
+
async processMessage(headers, payload) {
|
|
583
493
|
//eslint-disable-next-line consistent-this
|
|
584
494
|
const self = this;
|
|
585
495
|
const settings = this.settings;
|
|
586
|
-
const incomingMessageHeaders = this.readIncomingMessageHeaders(message);
|
|
587
496
|
|
|
588
497
|
self.messagesCount += 1;
|
|
589
498
|
|
|
590
499
|
const timeStart = Date.now();
|
|
591
500
|
|
|
592
|
-
const messageId = incomingMessageHeaders.messageId;
|
|
593
501
|
const logger = log.child({
|
|
594
|
-
threadId:
|
|
595
|
-
messageId: messageId || 'unknown',
|
|
596
|
-
parentMessageId:
|
|
597
|
-
...message.fields
|
|
502
|
+
threadId: headers.threadId || 'unknown',
|
|
503
|
+
messageId: headers.messageId || 'unknown',
|
|
504
|
+
parentMessageId: headers.parentMessageId || 'unknown'
|
|
598
505
|
});
|
|
599
506
|
|
|
600
|
-
if (messageId) {
|
|
601
|
-
const alreadyExists = messagesDB.getMessageById(messageId);
|
|
602
|
-
// Add message to DB even if it already exists
|
|
603
|
-
messagesDB.addMessage(messageId, message);
|
|
604
|
-
if (alreadyExists) {
|
|
605
|
-
logger.warn({ messageId }, 'Duplicate message detected. This'
|
|
606
|
-
+ ' delivery will be ignored; the handler that first received'
|
|
607
|
-
+ ' this message will process it as part of deduplication.');
|
|
608
|
-
// If message was in messagesDB, it means that the connection was closed
|
|
609
|
-
// and this message was redelivered. In this case, the process for original
|
|
610
|
-
// message is waiting for this message to be added to DB and then ack or
|
|
611
|
-
// nack the new message, instead of the one that was delivered by closed
|
|
612
|
-
// channel
|
|
613
|
-
return;
|
|
614
|
-
}
|
|
615
|
-
} else {
|
|
616
|
-
logger.warn('Message does not have messageId');
|
|
617
|
-
}
|
|
618
|
-
|
|
619
507
|
logger.trace({ messagesCount: this.messagesCount }, 'processMessage received');
|
|
620
508
|
|
|
621
509
|
const stepData = this.stepData;
|
|
@@ -623,10 +511,10 @@ class Sailor {
|
|
|
623
511
|
log.debug('Trigger or action: %s', settings.FUNCTION);
|
|
624
512
|
const outgoingMessageId = uuid.v4();
|
|
625
513
|
const outgoingMessageHeaders = {
|
|
626
|
-
...
|
|
514
|
+
...headers,
|
|
627
515
|
...getAdditionalHeadersFromSettings(settings),
|
|
628
|
-
parentMessageId:
|
|
629
|
-
threadId:
|
|
516
|
+
parentMessageId: headers.messageId,
|
|
517
|
+
threadId: headers.threadId,
|
|
630
518
|
messageId: outgoingMessageId,
|
|
631
519
|
execId: settings.EXEC_ID,
|
|
632
520
|
taskId: settings.FLOW_ID,
|
|
@@ -644,10 +532,8 @@ class Sailor {
|
|
|
644
532
|
} catch (e) {
|
|
645
533
|
log.error(e);
|
|
646
534
|
outgoingMessageHeaders.end = new Date().getTime();
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
self.amqpConnection.reject(messageId)
|
|
650
|
-
]);
|
|
535
|
+
self.proxyClient.sendError(e, outgoingMessageHeaders, payload, headers);
|
|
536
|
+
self.proxyClient.finishProcessing(headers, MESSAGE_PROCESSING_STATUS.ERROR);
|
|
651
537
|
return;
|
|
652
538
|
}
|
|
653
539
|
|
|
@@ -660,12 +546,12 @@ class Sailor {
|
|
|
660
546
|
await Promise.all([
|
|
661
547
|
(async () => {
|
|
662
548
|
logger.trace('Going to check if incoming message body is lightweight.');
|
|
663
|
-
payload.body = await this.fetchMessageBody(payload, logger);
|
|
549
|
+
payload.body = await this.proxyClient.fetchMessageBody(payload, logger);
|
|
664
550
|
})(),
|
|
665
551
|
...(passthrough
|
|
666
552
|
? Object.keys(passthrough).map(async stepId => {
|
|
667
553
|
logger.trace('Going to check if passthrough for step is lightweight.', { stepId });
|
|
668
|
-
payload.passthrough[stepId].body = await this.fetchMessageBody(
|
|
554
|
+
payload.passthrough[stepId].body = await this.proxyClient.fetchMessageBody(
|
|
669
555
|
payload.passthrough[stepId],
|
|
670
556
|
logger
|
|
671
557
|
);
|
|
@@ -675,15 +561,13 @@ class Sailor {
|
|
|
675
561
|
} catch (e) {
|
|
676
562
|
logger.error(e);
|
|
677
563
|
outgoingMessageHeaders.end = new Date().getTime();
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
self.amqpConnection.reject(messageId)
|
|
681
|
-
]);
|
|
564
|
+
self.proxyClient.sendError(e, outgoingMessageHeaders, payload, headers);
|
|
565
|
+
self.proxyClient.finishProcessing(headers, MESSAGE_PROCESSING_STATUS.ERROR);
|
|
682
566
|
return;
|
|
683
567
|
}
|
|
684
568
|
}
|
|
685
569
|
|
|
686
|
-
await this.runExec(module, payload,
|
|
570
|
+
await this.runExec(module, payload, headers, outgoingMessageHeaders, stepData, timeStart, logger);
|
|
687
571
|
}
|
|
688
572
|
}
|
|
689
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"
|