elasticio-sailor-nodejs 3.0.0-dev5 → 3.0.0-dev6
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/config/local.json +6 -6
- package/lib/proxy-client.js +123 -164
- package/lib/sailor.js +1 -1
- package/package.json +1 -1
package/config/local.json
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
{
|
|
2
2
|
"LOG_LEVEL": "trace",
|
|
3
3
|
"ELASTICIO_FLOW_ID": "692ee23d4ab5d34bb7321559",
|
|
4
|
-
"ELASTICIO_EXEC_ID": "
|
|
4
|
+
"ELASTICIO_EXEC_ID": "69b26526c4796609ca0da12a",
|
|
5
5
|
"ELASTICIO_STEP_ID": "step_1",
|
|
6
|
-
"ELASTICIO_CONTAINER_ID": "
|
|
7
|
-
"ELASTICIO_WORKSPACE_ID": "
|
|
8
|
-
"ELASTICIO_USER_ID": "
|
|
9
|
-
"ELASTICIO_COMP_ID": "
|
|
6
|
+
"ELASTICIO_CONTAINER_ID": "69b26526c4796609ca0da129",
|
|
7
|
+
"ELASTICIO_WORKSPACE_ID": "69b26526c4796609ca0da128",
|
|
8
|
+
"ELASTICIO_USER_ID": "69b26526c4796609ca0da127",
|
|
9
|
+
"ELASTICIO_COMP_ID": "69b26526c4796609ca0da126",
|
|
10
10
|
"ELASTICIO_FUNCTION": "data_trigger",
|
|
11
11
|
"ELASTICIO_API_URI": "http://localhost:9000",
|
|
12
12
|
"ELASTICIO_API_USERNAME": "task-692ee23d4ab5d34bb7321559",
|
|
13
13
|
"ELASTICIO_API_KEY": "976ffec8-455b-494e-9478-2d66761f4040",
|
|
14
14
|
"ELASTICIO_MESSAGE_CRYPTO_IV": "0.03091345790184",
|
|
15
15
|
"ELASTICIO_MESSAGE_CRYPTO_PASSWORD": "password",
|
|
16
|
-
"ELASTICIO_SAILOR_PROXY_URI": "http://localhost:
|
|
16
|
+
"ELASTICIO_SAILOR_PROXY_URI": "http://localhost:4001",
|
|
17
17
|
"ELASTICIO_COMPONENT_PATH": "./spec/component",
|
|
18
18
|
"ELASTICIO_EMIT_LIGHTWEIGHT_MESSAGE": "true"
|
|
19
19
|
}
|
package/lib/proxy-client.js
CHANGED
|
@@ -238,62 +238,16 @@ class ProxyClient {
|
|
|
238
238
|
throw new Error('Connection lost and no reconnection in progress');
|
|
239
239
|
}
|
|
240
240
|
|
|
241
|
-
async
|
|
242
|
-
await this._ensureConnection();
|
|
243
|
-
|
|
244
|
-
const { body, headers } = message;
|
|
245
|
-
|
|
246
|
-
logger.info('Checking if incoming messages is lightweight...');
|
|
247
|
-
|
|
248
|
-
if (!headers) {
|
|
249
|
-
logger.info('Empty headers so not lightweight.');
|
|
250
|
-
return body;
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
const { [OBJECT_ID_HEADER]: objectId } = headers;
|
|
254
|
-
|
|
255
|
-
if (!objectId) {
|
|
256
|
-
logger.trace('No object id header so not lightweight.');
|
|
257
|
-
return body;
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
logger.info('Object id header found, message is lightweight.', { objectId });
|
|
261
|
-
|
|
262
|
-
let object;
|
|
263
|
-
|
|
264
|
-
logger.info('Going to fetch message body.', { objectId });
|
|
265
|
-
|
|
241
|
+
async _proxyRequestWithRetries(operationName, requestFn) {
|
|
266
242
|
const maxRetries = this.settings.PROXY_OBJECT_REQUEST_RETRY_ATTEMPTS;
|
|
267
243
|
const retryDelay = this.settings.PROXY_OBJECT_REQUEST_RETRY_DELAY;
|
|
268
244
|
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
269
245
|
try {
|
|
270
|
-
|
|
271
|
-
const getObjectStream = this.clientSession.request({
|
|
272
|
-
[HTTP2_HEADER_PATH]: `/object/${objectId}`,
|
|
273
|
-
[HTTP2_HEADER_METHOD]: 'GET',
|
|
274
|
-
[HTTP2_HEADER_AUTHORIZATION]: this.authHeader
|
|
275
|
-
}).pipe(this._encryptor.createDecipher());
|
|
276
|
-
|
|
277
|
-
const chunks = [];
|
|
278
|
-
getObjectStream.on('data', chunk => {
|
|
279
|
-
chunks.push(chunk);
|
|
280
|
-
});
|
|
281
|
-
getObjectStream.on('error', (err) => {
|
|
282
|
-
logger.error(err, 'Error during fetching message body');
|
|
283
|
-
reject(err);
|
|
284
|
-
});
|
|
285
|
-
getObjectStream.on('end', () => {
|
|
286
|
-
logger.info('Message stream ended by server');
|
|
287
|
-
const buffer = Buffer.concat(chunks);
|
|
288
|
-
logger.info({ messageSize: buffer.length }, 'Received complete message from server');
|
|
289
|
-
resolve({ data: JSON.parse(buffer.toString()) });
|
|
290
|
-
});
|
|
291
|
-
});
|
|
292
|
-
|
|
246
|
+
const result = await requestFn();
|
|
293
247
|
if (attempt > 0) {
|
|
294
|
-
log.info({ attempt, maxRetries },
|
|
248
|
+
log.info({ attempt, maxRetries }, `${operationName} succeeded after retry`);
|
|
295
249
|
}
|
|
296
|
-
return
|
|
250
|
+
return result;
|
|
297
251
|
} catch (error) {
|
|
298
252
|
const isLastAttempt = attempt === maxRetries;
|
|
299
253
|
const isRetryable = error.isNetworkError ||
|
|
@@ -307,7 +261,7 @@ class ProxyClient {
|
|
|
307
261
|
maxRetries,
|
|
308
262
|
error: error.message,
|
|
309
263
|
isRetryable
|
|
310
|
-
},
|
|
264
|
+
}, `${operationName} failed, no more retries`);
|
|
311
265
|
throw error;
|
|
312
266
|
}
|
|
313
267
|
|
|
@@ -320,121 +274,120 @@ class ProxyClient {
|
|
|
320
274
|
maxRetries,
|
|
321
275
|
error: error.message,
|
|
322
276
|
nextRetryIn: delay
|
|
323
|
-
},
|
|
277
|
+
}, `${operationName} failed, retrying...`);
|
|
324
278
|
|
|
325
279
|
await new Promise(resolve => setTimeout(resolve, delay));
|
|
326
280
|
|
|
327
|
-
// Ensure connection is still valid before retry
|
|
328
281
|
if (!this.isConnected()) {
|
|
329
282
|
log.info('Reconnecting before retry...');
|
|
330
283
|
await this.connect();
|
|
331
284
|
}
|
|
332
285
|
}
|
|
333
286
|
}
|
|
334
|
-
logger.info('Successfully obtained message body.', { objectId });
|
|
335
|
-
logger.trace('Message body object received');
|
|
336
|
-
|
|
337
|
-
return object.data;
|
|
338
287
|
}
|
|
339
288
|
|
|
340
|
-
async
|
|
289
|
+
async fetchMessageBody(message, logger) {
|
|
341
290
|
await this._ensureConnection();
|
|
342
291
|
|
|
343
|
-
const
|
|
344
|
-
const retryDelay = this.settings.PROXY_OBJECT_REQUEST_RETRY_DELAY;
|
|
345
|
-
for (let attempt = 0; attempt <= maxRetries; attempt++) {
|
|
346
|
-
try {
|
|
347
|
-
const objectId = await new Promise((resolve, reject) => {
|
|
348
|
-
const postMessageStream = this.clientSession.request({
|
|
349
|
-
[HTTP2_HEADER_PATH]: '/object',
|
|
350
|
-
[HTTP2_HEADER_METHOD]: 'POST',
|
|
351
|
-
[HTTP2_HEADER_AUTHORIZATION]: this.authHeader
|
|
352
|
-
});
|
|
292
|
+
const { body, headers } = message;
|
|
353
293
|
|
|
354
|
-
|
|
355
|
-
let statusCode = null;
|
|
294
|
+
logger.info('Checking if incoming messages is lightweight...');
|
|
356
295
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
error.statusCode = statusCode;
|
|
362
|
-
return reject(error);
|
|
363
|
-
}
|
|
364
|
-
});
|
|
296
|
+
if (!headers) {
|
|
297
|
+
logger.info('Empty headers so not lightweight.');
|
|
298
|
+
return body;
|
|
299
|
+
}
|
|
365
300
|
|
|
366
|
-
|
|
367
|
-
responseData += chunk;
|
|
368
|
-
});
|
|
301
|
+
const { [OBJECT_ID_HEADER]: objectId } = headers;
|
|
369
302
|
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
});
|
|
303
|
+
if (!objectId) {
|
|
304
|
+
logger.trace('No object id header so not lightweight.');
|
|
305
|
+
return body;
|
|
306
|
+
}
|
|
375
307
|
|
|
376
|
-
|
|
377
|
-
if (!responseData) {
|
|
378
|
-
return
|
|
379
|
-
}
|
|
380
|
-
try {
|
|
381
|
-
const responseJson = JSON.parse(responseData);
|
|
382
|
-
resolve(responseJson.objectId);
|
|
383
|
-
} catch (e) {
|
|
384
|
-
log.error(e, 'Failed to parse upload message body response');
|
|
385
|
-
reject(e);
|
|
386
|
-
}
|
|
387
|
-
});
|
|
308
|
+
logger.info('Object id header found, message is lightweight.', { objectId });
|
|
388
309
|
|
|
389
|
-
|
|
390
|
-
cipher.pipe(postMessageStream);
|
|
391
|
-
cipher.write(bodyBuf);
|
|
392
|
-
cipher.end();
|
|
393
|
-
});
|
|
310
|
+
logger.info('Going to fetch message body.', { objectId });
|
|
394
311
|
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
312
|
+
await this._proxyRequestWithRetries('Fetch message body', () => new Promise((resolve, reject) => {
|
|
313
|
+
const getObjectStream = this.clientSession.request({
|
|
314
|
+
[HTTP2_HEADER_PATH]: `/object/${objectId}`,
|
|
315
|
+
[HTTP2_HEADER_METHOD]: 'GET',
|
|
316
|
+
[HTTP2_HEADER_AUTHORIZATION]: this.authHeader
|
|
317
|
+
}).pipe(this._encryptor.createDecipher());
|
|
400
318
|
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
319
|
+
const chunks = [];
|
|
320
|
+
getObjectStream.on('data', chunk => {
|
|
321
|
+
chunks.push(chunk);
|
|
322
|
+
});
|
|
323
|
+
getObjectStream.on('error', (err) => {
|
|
324
|
+
logger.error(err, 'Error during fetching message body');
|
|
325
|
+
reject(err);
|
|
326
|
+
});
|
|
327
|
+
getObjectStream.on('end', () => {
|
|
328
|
+
logger.info('Message stream ended by server');
|
|
329
|
+
const buffer = Buffer.concat(chunks);
|
|
330
|
+
logger.info({ messageSize: buffer.length }, 'Received complete message from server');
|
|
331
|
+
resolve({ data: JSON.parse(buffer.toString()) });
|
|
332
|
+
});
|
|
333
|
+
}));
|
|
407
334
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
335
|
+
logger.info('Successfully obtained message body.', { objectId });
|
|
336
|
+
logger.trace('Message body object received');
|
|
337
|
+
|
|
338
|
+
return objectId;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
async uploadMessageBody(bodyBuf) {
|
|
342
|
+
await this._ensureConnection();
|
|
343
|
+
|
|
344
|
+
return this._proxyRequestWithRetries('Upload message body', () => new Promise((resolve, reject) => {
|
|
345
|
+
const postMessageStream = this.clientSession.request({
|
|
346
|
+
[HTTP2_HEADER_PATH]: '/object',
|
|
347
|
+
[HTTP2_HEADER_METHOD]: 'POST',
|
|
348
|
+
[HTTP2_HEADER_AUTHORIZATION]: this.authHeader
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
let responseData = '';
|
|
352
|
+
let statusCode = null;
|
|
353
|
+
|
|
354
|
+
postMessageStream.on('response', (headers, flags) => {
|
|
355
|
+
statusCode = headers[http2.constants.HTTP2_HEADER_STATUS];
|
|
356
|
+
if (statusCode !== 200) {
|
|
357
|
+
const error = new Error(`Failed to upload message body, status code: ${statusCode}`);
|
|
358
|
+
error.statusCode = statusCode;
|
|
359
|
+
return reject(error);
|
|
416
360
|
}
|
|
361
|
+
});
|
|
417
362
|
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
);
|
|
422
|
-
log.warn({
|
|
423
|
-
attempt,
|
|
424
|
-
maxRetries,
|
|
425
|
-
error: error.message,
|
|
426
|
-
nextRetryIn: delay
|
|
427
|
-
}, 'Upload message body failed, retrying...');
|
|
363
|
+
postMessageStream.on('data', chunk => {
|
|
364
|
+
responseData += chunk;
|
|
365
|
+
});
|
|
428
366
|
|
|
429
|
-
|
|
367
|
+
postMessageStream.on('error', (err) => {
|
|
368
|
+
log.error(err, 'Error during upload message body');
|
|
369
|
+
err.isNetworkError = true;
|
|
370
|
+
reject(err);
|
|
371
|
+
});
|
|
430
372
|
|
|
431
|
-
|
|
432
|
-
if (!
|
|
433
|
-
|
|
434
|
-
await this.connect();
|
|
373
|
+
postMessageStream.on('end', () => {
|
|
374
|
+
if (!responseData) {
|
|
375
|
+
return
|
|
435
376
|
}
|
|
436
|
-
|
|
437
|
-
|
|
377
|
+
try {
|
|
378
|
+
const responseJson = JSON.parse(responseData);
|
|
379
|
+
resolve(responseJson.objectId);
|
|
380
|
+
} catch (e) {
|
|
381
|
+
log.error(e, 'Failed to parse upload message body response');
|
|
382
|
+
reject(e);
|
|
383
|
+
}
|
|
384
|
+
});
|
|
385
|
+
|
|
386
|
+
const cipher = this._encryptor.createCipher();
|
|
387
|
+
cipher.pipe(postMessageStream);
|
|
388
|
+
cipher.write(bodyBuf);
|
|
389
|
+
cipher.end();
|
|
390
|
+
}));
|
|
438
391
|
}
|
|
439
392
|
|
|
440
393
|
async listenForMessages(messageHandler) {
|
|
@@ -543,33 +496,36 @@ class ProxyClient {
|
|
|
543
496
|
type,
|
|
544
497
|
...(customRoutingKey ? { customRoutingKey } : {})
|
|
545
498
|
}).toString();
|
|
546
|
-
// TODO: Add retries
|
|
547
|
-
const postMessageStream = this.clientSession.request({
|
|
548
|
-
...proxyHeaders,
|
|
549
|
-
[HTTP2_HEADER_PATH]: `/message?${queryParams}`,
|
|
550
|
-
[HTTP2_HEADER_METHOD]: 'POST',
|
|
551
|
-
[HTTP2_HEADER_AUTHORIZATION]: this.authHeader
|
|
552
|
-
});
|
|
553
|
-
postMessageStream.write(encryptedData);
|
|
554
|
-
postMessageStream.end();
|
|
555
499
|
|
|
556
|
-
|
|
500
|
+
await this._proxyRequestWithRetries('Send message', () => new Promise((resolve, reject) => {
|
|
501
|
+
const postMessageStream = this.clientSession.request({
|
|
502
|
+
...proxyHeaders,
|
|
503
|
+
[HTTP2_HEADER_PATH]: `/message?${queryParams}`,
|
|
504
|
+
[HTTP2_HEADER_METHOD]: 'POST',
|
|
505
|
+
[HTTP2_HEADER_AUTHORIZATION]: this.authHeader
|
|
506
|
+
});
|
|
507
|
+
postMessageStream.write(encryptedData);
|
|
508
|
+
postMessageStream.end();
|
|
509
|
+
|
|
557
510
|
postMessageStream.on('response', (headers) => {
|
|
558
511
|
log.debug({ status: headers[HTTP2_HEADER_STATUS] }, 'Send message response');
|
|
559
512
|
if (headers[HTTP2_HEADER_STATUS] !== 200) {
|
|
560
513
|
log.error({ headers }, 'Failed to send message');
|
|
561
|
-
|
|
514
|
+
const error = new Error(`Failed to send message, status code: ${headers[HTTP2_HEADER_STATUS]}`);
|
|
515
|
+
error.statusCode = headers[HTTP2_HEADER_STATUS];
|
|
516
|
+
return reject(error);
|
|
562
517
|
}
|
|
563
518
|
});
|
|
564
519
|
postMessageStream.on('error', (err) => {
|
|
565
520
|
log.error(err, 'Error during sending message');
|
|
521
|
+
err.isNetworkError = true;
|
|
566
522
|
reject(err);
|
|
567
523
|
});
|
|
568
524
|
postMessageStream.on('end', () => {
|
|
569
525
|
log.debug('Send message end event');
|
|
570
526
|
resolve();
|
|
571
527
|
});
|
|
572
|
-
});
|
|
528
|
+
}));
|
|
573
529
|
}
|
|
574
530
|
|
|
575
531
|
_decodeMessage(originalMessage, headers) {
|
|
@@ -621,30 +577,33 @@ class ProxyClient {
|
|
|
621
577
|
incomingMessageId,
|
|
622
578
|
status
|
|
623
579
|
}).toString();
|
|
624
|
-
// TODO: Add retries
|
|
625
|
-
const postMessageStream = this.clientSession.request({
|
|
626
|
-
[HTTP2_HEADER_PATH]: `/finish-processing?${queryParams}`,
|
|
627
|
-
[HTTP2_HEADER_METHOD]: 'POST',
|
|
628
|
-
[HTTP2_HEADER_AUTHORIZATION]: this.authHeader
|
|
629
|
-
});
|
|
630
|
-
postMessageStream.end();
|
|
631
580
|
|
|
632
|
-
|
|
581
|
+
await this._proxyRequestWithRetries('Finish processing', () => new Promise((resolve, reject) => {
|
|
582
|
+
const postMessageStream = this.clientSession.request({
|
|
583
|
+
[HTTP2_HEADER_PATH]: `/finish-processing?${queryParams}`,
|
|
584
|
+
[HTTP2_HEADER_METHOD]: 'POST',
|
|
585
|
+
[HTTP2_HEADER_AUTHORIZATION]: this.authHeader
|
|
586
|
+
});
|
|
587
|
+
postMessageStream.end();
|
|
588
|
+
|
|
633
589
|
postMessageStream.on('response', (headers) => {
|
|
634
590
|
log.debug({ status: headers[HTTP2_HEADER_STATUS] }, 'Finish processing response event');
|
|
635
591
|
if (headers[HTTP2_HEADER_STATUS] !== 200) {
|
|
636
592
|
log.error({ headers }, 'Failed to finish processing message');
|
|
637
|
-
|
|
593
|
+
const error = new Error(`Failed to finish processing message, status code: ${headers[HTTP2_HEADER_STATUS]}`);
|
|
594
|
+
error.statusCode = headers[HTTP2_HEADER_STATUS];
|
|
595
|
+
return reject(error);
|
|
638
596
|
}
|
|
639
597
|
});
|
|
640
|
-
|
|
641
598
|
postMessageStream.on('end', () => {
|
|
642
599
|
log.debug('Finish processing end event');
|
|
643
600
|
resolve();
|
|
644
601
|
});
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
602
|
+
postMessageStream.on('error', (err) => {
|
|
603
|
+
err.isNetworkError = true;
|
|
604
|
+
reject(err);
|
|
605
|
+
});
|
|
606
|
+
}));
|
|
648
607
|
}
|
|
649
608
|
|
|
650
609
|
encryptMessageContent(body, protocolVersion = 1) {
|
package/lib/sailor.js
CHANGED
|
@@ -80,6 +80,7 @@ class Sailor {
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
async disconnect() {
|
|
83
|
+
// TODO: delete if not needed (currently used only in old tests)
|
|
83
84
|
log.debug('Disconnecting, %s messages in processing', this.messagesCount);
|
|
84
85
|
return this.proxyClient.disconnect();
|
|
85
86
|
}
|
|
@@ -194,7 +195,6 @@ class Sailor {
|
|
|
194
195
|
return new Promise(resolve => this.shutdownCallback = resolve);
|
|
195
196
|
}
|
|
196
197
|
|
|
197
|
-
// TODO: remove duplicate disconnect call (also in run.js)
|
|
198
198
|
await this.proxyClient.disconnect();
|
|
199
199
|
if (this.messagesCount === 0) {
|
|
200
200
|
// there is no unfinished processMessage invocation, let's just resolve scheduleShutdown now
|
package/package.json
CHANGED