elasticio-sailor-nodejs 3.0.0-dev7.1 → 3.0.0-sailor-proxy-dev2
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 +757 -0
- package/lib/sailor.js +74 -204
- package/lib/settings.js +17 -20
- package/lib/utils.js +8 -0
- package/package.json +8 -6
- package/run.js +33 -37
- package/run.local.js +16 -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,
|
|
@@ -102,10 +81,10 @@ class Sailor {
|
|
|
102
81
|
|
|
103
82
|
async disconnect() {
|
|
104
83
|
log.debug('Disconnecting, %s messages in processing', this.messagesCount);
|
|
105
|
-
return this.
|
|
84
|
+
return this.proxyClient.disconnect();
|
|
106
85
|
}
|
|
107
86
|
|
|
108
|
-
|
|
87
|
+
reportError(err) {
|
|
109
88
|
const headers = Object.assign({}, getAdditionalHeadersFromSettings(this.settings), {
|
|
110
89
|
execId: this.settings.EXEC_ID,
|
|
111
90
|
taskId: this.settings.FLOW_ID,
|
|
@@ -116,7 +95,7 @@ class Sailor {
|
|
|
116
95
|
compId: this.settings.COMP_ID,
|
|
117
96
|
function: this.settings.FUNCTION
|
|
118
97
|
});
|
|
119
|
-
return this.
|
|
98
|
+
return this.proxyClient.sendError(err, headers);
|
|
120
99
|
}
|
|
121
100
|
|
|
122
101
|
startup() {
|
|
@@ -184,18 +163,20 @@ class Sailor {
|
|
|
184
163
|
}
|
|
185
164
|
|
|
186
165
|
run() {
|
|
187
|
-
const incomingQueue = this.settings.LISTEN_MESSAGES_ON;
|
|
188
166
|
const handler = this.processMessageAndMaybeShutdownCallback.bind(this);
|
|
189
|
-
log.debug('Start listening for messages
|
|
190
|
-
return this.
|
|
167
|
+
log.debug('Start listening for messages');
|
|
168
|
+
return this.proxyClient.listenForMessages(handler);
|
|
191
169
|
}
|
|
192
170
|
|
|
193
|
-
async processMessageAndMaybeShutdownCallback(
|
|
171
|
+
async processMessageAndMaybeShutdownCallback(headers, body) {
|
|
194
172
|
try {
|
|
195
|
-
|
|
173
|
+
await this.processMessage(headers, body);
|
|
196
174
|
} catch (e) {
|
|
197
|
-
log.error('Something very bad happened during message processing');
|
|
175
|
+
log.error(e, 'Something very bad happened during message processing');
|
|
198
176
|
} finally {
|
|
177
|
+
log.debug({
|
|
178
|
+
messagesCount: this.messagesCount
|
|
179
|
+
}, 'Finished processing message, checking if shutdownCallback should be called');
|
|
199
180
|
if (this.shutdownCallback) {
|
|
200
181
|
if (this.messagesCount === 0) {
|
|
201
182
|
// there is no another processMessage invocation, so it's time to call shutdownCallback
|
|
@@ -216,7 +197,7 @@ class Sailor {
|
|
|
216
197
|
return new Promise(resolve => this.shutdownCallback = resolve);
|
|
217
198
|
}
|
|
218
199
|
|
|
219
|
-
await this.
|
|
200
|
+
await this.proxyClient.stopListeningForMessages();
|
|
220
201
|
if (this.messagesCount === 0) {
|
|
221
202
|
// there is no unfinished processMessage invocation, let's just resolve scheduleShutdown now
|
|
222
203
|
log.debug('scheduleShutdown – about to shutdown immediately');
|
|
@@ -228,103 +209,23 @@ class Sailor {
|
|
|
228
209
|
return new Promise(resolve => this.shutdownCallback = resolve);
|
|
229
210
|
}
|
|
230
211
|
|
|
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) {
|
|
212
|
+
async runExec(module, payload, incomingMessageHeaders, outgoingMessageHeaders, stepData, timeStart, logger) {
|
|
213
|
+
log.debug({ incomingMessageHeaders }, 'runExec started');
|
|
308
214
|
const origPassthrough = _.cloneDeep(payload.passthrough) || {};
|
|
309
|
-
const incomingMessageHeaders = this.readIncomingMessageHeaders(message);
|
|
310
|
-
const messageId = incomingMessageHeaders.messageId;
|
|
311
215
|
const settings = this.settings;
|
|
312
216
|
const cfg = _.cloneDeep(stepData.config) || {};
|
|
313
217
|
const snapshot = _.cloneDeep(this.snapshot);
|
|
314
|
-
const { deliveryTag } = message.fields;
|
|
315
218
|
|
|
316
219
|
const that = this;
|
|
317
220
|
|
|
318
221
|
await new Promise(resolve => {
|
|
319
222
|
let endWasEmitted;
|
|
320
223
|
|
|
321
|
-
|
|
322
224
|
const taskExec = new TaskExec({
|
|
323
225
|
loggerOptions: _.pick(incomingMessageHeaders, ['threadId', 'messageId', 'parentMessageId']),
|
|
324
226
|
variables: stepData.variables,
|
|
325
227
|
services: {
|
|
326
228
|
apiClient: this.apiClient,
|
|
327
|
-
amqp: this.amqpConnection,
|
|
328
229
|
config: this.settings
|
|
329
230
|
}
|
|
330
231
|
});
|
|
@@ -391,34 +292,18 @@ class Sailor {
|
|
|
391
292
|
let passthroughIds;
|
|
392
293
|
try {
|
|
393
294
|
[bodyId, ...passthroughIds] = await Promise.all([
|
|
394
|
-
that.uploadMessageBody(bodyBuf),
|
|
295
|
+
that.proxyClient.uploadMessageBody(bodyBuf),
|
|
395
296
|
...passthroughBufs.map(async ({ stepId, body, id }) => {
|
|
396
|
-
const
|
|
397
|
-
return { stepId, bodyId
|
|
297
|
+
const bodyId = id || await that.proxyClient.uploadMessageBody(body);
|
|
298
|
+
return { stepId, bodyId };
|
|
398
299
|
})
|
|
399
300
|
]);
|
|
400
301
|
} 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
|
-
);
|
|
302
|
+
logger.error(e, 'Error during message/passthrough body upload');
|
|
303
|
+
return onError(new Error('Lightweight message/passthrough body upload error'));
|
|
419
304
|
}
|
|
420
305
|
|
|
421
|
-
logger.info(
|
|
306
|
+
logger.info({ id: bodyId }, 'Message body uploaded');
|
|
422
307
|
const { headers } = data;
|
|
423
308
|
data.body = {};
|
|
424
309
|
data.headers = {
|
|
@@ -455,7 +340,7 @@ class Sailor {
|
|
|
455
340
|
logger.trace('Body is not empty.', { stepId });
|
|
456
341
|
return;
|
|
457
342
|
}
|
|
458
|
-
data.passthrough[stepId].body = await that.fetchMessageBody(
|
|
343
|
+
data.passthrough[stepId].body = await that.proxyClient.fetchMessageBody(
|
|
459
344
|
passthrough[stepId],
|
|
460
345
|
logger
|
|
461
346
|
);
|
|
@@ -474,7 +359,12 @@ class Sailor {
|
|
|
474
359
|
log.trace('Going to send outgoing message');
|
|
475
360
|
|
|
476
361
|
try {
|
|
477
|
-
await that.
|
|
362
|
+
await that.proxyClient.sendMessage({
|
|
363
|
+
incomingMessageId: incomingMessageHeaders.messageId,
|
|
364
|
+
data,
|
|
365
|
+
headers,
|
|
366
|
+
type: 'data'
|
|
367
|
+
});
|
|
478
368
|
log.trace('Outgoing message sent');
|
|
479
369
|
} catch (err) {
|
|
480
370
|
return onError(err);
|
|
@@ -487,7 +377,12 @@ class Sailor {
|
|
|
487
377
|
messageProcessingTime: Date.now() - timeStart
|
|
488
378
|
}, 'processMessage emit HttpReply');
|
|
489
379
|
|
|
490
|
-
return that.
|
|
380
|
+
return that.proxyClient.sendMessage({
|
|
381
|
+
incomingMessageId: incomingMessageHeaders.messageId,
|
|
382
|
+
data: reply,
|
|
383
|
+
headers,
|
|
384
|
+
type: 'http-reply'
|
|
385
|
+
});
|
|
491
386
|
}
|
|
492
387
|
|
|
493
388
|
async function onError(err) {
|
|
@@ -500,7 +395,7 @@ class Sailor {
|
|
|
500
395
|
messageProcessingTime: Date.now() - timeStart
|
|
501
396
|
}, 'processMessage emit error');
|
|
502
397
|
headers.end = new Date().getTime();
|
|
503
|
-
return that.
|
|
398
|
+
return that.proxyClient.sendError(err, headers, payload, incomingMessageHeaders);
|
|
504
399
|
}
|
|
505
400
|
|
|
506
401
|
async function onRebound(err) {
|
|
@@ -511,14 +406,14 @@ class Sailor {
|
|
|
511
406
|
messagesCount: that.messagesCount,
|
|
512
407
|
messageProcessingTime: Date.now() - timeStart
|
|
513
408
|
}, 'processMessage emit rebound');
|
|
514
|
-
return that.
|
|
409
|
+
return that.proxyClient.sendRebound(err, incomingMessageHeaders, outgoingHeaders);
|
|
515
410
|
}
|
|
516
411
|
|
|
517
412
|
async function onSnapshot(data) {
|
|
518
413
|
const headers = _.clone(outgoingMessageHeaders);
|
|
519
414
|
headers.snapshotEvent = 'snapshot';
|
|
520
415
|
that.snapshot = data; //replacing `local` snapshot
|
|
521
|
-
return that.
|
|
416
|
+
return that.proxyClient.sendSnapshot(data, headers);
|
|
522
417
|
}
|
|
523
418
|
|
|
524
419
|
async function onUpdateSnapshot(data) {
|
|
@@ -530,7 +425,7 @@ class Sailor {
|
|
|
530
425
|
return log.warn('ERROR: $set is not supported any more in `updateSnapshot` event');
|
|
531
426
|
}
|
|
532
427
|
_.extend(that.snapshot, data); //updating `local` snapshot
|
|
533
|
-
return that.
|
|
428
|
+
return that.proxyClient.sendSnapshot(data, headers);
|
|
534
429
|
} else {
|
|
535
430
|
log.error('You should pass an object to the `updateSnapshot` event');
|
|
536
431
|
}
|
|
@@ -543,9 +438,9 @@ class Sailor {
|
|
|
543
438
|
|
|
544
439
|
try {
|
|
545
440
|
await that.apiClient.accounts.update(cfg._account, { keys: keys });
|
|
546
|
-
logger.debug('Successfully updated keys
|
|
441
|
+
logger.debug({ messageId: incomingMessageHeaders.messageId }, 'Successfully updated keys');
|
|
547
442
|
} catch (error) {
|
|
548
|
-
logger.
|
|
443
|
+
logger.debug({ messageId: incomingMessageHeaders.messageId }, 'Failed to update keys');
|
|
549
444
|
await onError(error);
|
|
550
445
|
}
|
|
551
446
|
}
|
|
@@ -562,11 +457,12 @@ class Sailor {
|
|
|
562
457
|
|
|
563
458
|
endWasEmitted = true;
|
|
564
459
|
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
460
|
+
await that.proxyClient.finishProcessing(
|
|
461
|
+
incomingMessageHeaders,
|
|
462
|
+
taskExec.errorCount > 0
|
|
463
|
+
? MESSAGE_PROCESSING_STATUS.ERROR
|
|
464
|
+
: MESSAGE_PROCESSING_STATUS.SUCCESS
|
|
465
|
+
);
|
|
570
466
|
that.messagesCount -= 1;
|
|
571
467
|
logger.trace({
|
|
572
468
|
messagesCount: that.messagesCount,
|
|
@@ -595,43 +491,21 @@ class Sailor {
|
|
|
595
491
|
}
|
|
596
492
|
}
|
|
597
493
|
|
|
598
|
-
async processMessage(
|
|
494
|
+
async processMessage(headers, payload) {
|
|
599
495
|
//eslint-disable-next-line consistent-this
|
|
600
496
|
const self = this;
|
|
601
497
|
const settings = this.settings;
|
|
602
|
-
const incomingMessageHeaders = this.readIncomingMessageHeaders(message);
|
|
603
498
|
|
|
604
499
|
self.messagesCount += 1;
|
|
605
500
|
|
|
606
501
|
const timeStart = Date.now();
|
|
607
502
|
|
|
608
|
-
const messageId = incomingMessageHeaders.messageId;
|
|
609
503
|
const logger = log.child({
|
|
610
|
-
threadId:
|
|
611
|
-
messageId: messageId || 'unknown',
|
|
612
|
-
parentMessageId:
|
|
613
|
-
...message.fields
|
|
504
|
+
threadId: headers.threadId || 'unknown',
|
|
505
|
+
messageId: headers.messageId || 'unknown',
|
|
506
|
+
parentMessageId: headers.parentMessageId || 'unknown'
|
|
614
507
|
});
|
|
615
508
|
|
|
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
509
|
logger.trace({ messagesCount: this.messagesCount }, 'processMessage received');
|
|
636
510
|
|
|
637
511
|
const stepData = this.stepData;
|
|
@@ -639,10 +513,10 @@ class Sailor {
|
|
|
639
513
|
log.debug('Trigger or action: %s', settings.FUNCTION);
|
|
640
514
|
const outgoingMessageId = uuid.v4();
|
|
641
515
|
const outgoingMessageHeaders = {
|
|
642
|
-
...
|
|
516
|
+
...headers,
|
|
643
517
|
...getAdditionalHeadersFromSettings(settings),
|
|
644
|
-
parentMessageId:
|
|
645
|
-
threadId:
|
|
518
|
+
parentMessageId: headers.messageId,
|
|
519
|
+
threadId: headers.threadId,
|
|
646
520
|
messageId: outgoingMessageId,
|
|
647
521
|
execId: settings.EXEC_ID,
|
|
648
522
|
taskId: settings.FLOW_ID,
|
|
@@ -660,10 +534,8 @@ class Sailor {
|
|
|
660
534
|
} catch (e) {
|
|
661
535
|
log.error(e);
|
|
662
536
|
outgoingMessageHeaders.end = new Date().getTime();
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
self.amqpConnection.reject(messageId)
|
|
666
|
-
]);
|
|
537
|
+
self.proxyClient.sendError(e, outgoingMessageHeaders, payload, headers);
|
|
538
|
+
self.proxyClient.finishProcessing(headers, MESSAGE_PROCESSING_STATUS.ERROR);
|
|
667
539
|
return;
|
|
668
540
|
}
|
|
669
541
|
|
|
@@ -676,12 +548,12 @@ class Sailor {
|
|
|
676
548
|
await Promise.all([
|
|
677
549
|
(async () => {
|
|
678
550
|
logger.trace('Going to check if incoming message body is lightweight.');
|
|
679
|
-
payload.body = await this.fetchMessageBody(payload, logger);
|
|
551
|
+
payload.body = await this.proxyClient.fetchMessageBody(payload, logger);
|
|
680
552
|
})(),
|
|
681
553
|
...(passthrough
|
|
682
554
|
? Object.keys(passthrough).map(async stepId => {
|
|
683
555
|
logger.trace('Going to check if passthrough for step is lightweight.', { stepId });
|
|
684
|
-
payload.passthrough[stepId].body = await this.fetchMessageBody(
|
|
556
|
+
payload.passthrough[stepId].body = await this.proxyClient.fetchMessageBody(
|
|
685
557
|
payload.passthrough[stepId],
|
|
686
558
|
logger
|
|
687
559
|
);
|
|
@@ -691,15 +563,13 @@ class Sailor {
|
|
|
691
563
|
} catch (e) {
|
|
692
564
|
logger.error(e);
|
|
693
565
|
outgoingMessageHeaders.end = new Date().getTime();
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
self.amqpConnection.reject(messageId)
|
|
697
|
-
]);
|
|
566
|
+
self.proxyClient.sendError(e, outgoingMessageHeaders, payload, headers);
|
|
567
|
+
self.proxyClient.finishProcessing(headers, MESSAGE_PROCESSING_STATUS.ERROR);
|
|
698
568
|
return;
|
|
699
569
|
}
|
|
700
570
|
}
|
|
701
571
|
|
|
702
|
-
await this.runExec(module, payload,
|
|
572
|
+
await this.runExec(module, payload, headers, outgoingMessageHeaders, stepData, timeStart, logger);
|
|
703
573
|
}
|
|
704
574
|
}
|
|
705
575
|
|
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/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-dev2",
|
|
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"
|