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 CHANGED
@@ -1,19 +1,19 @@
1
1
  {
2
2
  "LOG_LEVEL": "trace",
3
3
  "ELASTICIO_FLOW_ID": "692ee23d4ab5d34bb7321559",
4
- "ELASTICIO_EXEC_ID": "exec_67890",
4
+ "ELASTICIO_EXEC_ID": "69b26526c4796609ca0da12a",
5
5
  "ELASTICIO_STEP_ID": "step_1",
6
- "ELASTICIO_CONTAINER_ID": "container_abcde",
7
- "ELASTICIO_WORKSPACE_ID": "workspace_xyz",
8
- "ELASTICIO_USER_ID": "user_1122",
9
- "ELASTICIO_COMP_ID": "component_3344",
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:5001",
16
+ "ELASTICIO_SAILOR_PROXY_URI": "http://localhost:4001",
17
17
  "ELASTICIO_COMPONENT_PATH": "./spec/component",
18
18
  "ELASTICIO_EMIT_LIGHTWEIGHT_MESSAGE": "true"
19
19
  }
@@ -238,62 +238,16 @@ class ProxyClient {
238
238
  throw new Error('Connection lost and no reconnection in progress');
239
239
  }
240
240
 
241
- async fetchMessageBody(message, logger) {
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
- object = await new Promise((resolve, reject) => {
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 }, 'Fetch message body succeeded after retry');
248
+ log.info({ attempt, maxRetries }, `${operationName} succeeded after retry`);
295
249
  }
296
- return objectId;
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
- }, 'Fetch message body failed, no more retries');
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
- }, 'Fetch message body failed, retrying...');
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 uploadMessageBody(bodyBuf) {
289
+ async fetchMessageBody(message, logger) {
341
290
  await this._ensureConnection();
342
291
 
343
- const maxRetries = this.settings.PROXY_OBJECT_REQUEST_RETRY_ATTEMPTS;
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
- let responseData = '';
355
- let statusCode = null;
294
+ logger.info('Checking if incoming messages is lightweight...');
356
295
 
357
- postMessageStream.on('response', (headers, flags) => {
358
- statusCode = headers[http2.constants.HTTP2_HEADER_STATUS];
359
- if (statusCode !== 200) {
360
- const error = new Error(`Failed to upload message body, status code: ${statusCode}`);
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
- postMessageStream.on('data', chunk => {
367
- responseData += chunk;
368
- });
301
+ const { [OBJECT_ID_HEADER]: objectId } = headers;
369
302
 
370
- postMessageStream.on('error', (err) => {
371
- log.error(err, 'Error during upload message body');
372
- err.isNetworkError = true;
373
- reject(err);
374
- });
303
+ if (!objectId) {
304
+ logger.trace('No object id header so not lightweight.');
305
+ return body;
306
+ }
375
307
 
376
- postMessageStream.on('end', () => {
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
- const cipher = this._encryptor.createCipher();
390
- cipher.pipe(postMessageStream);
391
- cipher.write(bodyBuf);
392
- cipher.end();
393
- });
310
+ logger.info('Going to fetch message body.', { objectId });
394
311
 
395
- // Success - return the objectId
396
- if (attempt > 0) {
397
- log.info({ attempt, maxRetries }, 'Upload message body succeeded after retry');
398
- }
399
- return objectId;
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
- } catch (error) {
402
- const isLastAttempt = attempt === maxRetries;
403
- const isRetryable = error.isNetworkError ||
404
- (error.statusCode && error.statusCode >= 500) ||
405
- error.code === 'ECONNRESET' ||
406
- error.code === 'ETIMEDOUT';
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
- if (!isRetryable || isLastAttempt) {
409
- log.error({
410
- attempt,
411
- maxRetries,
412
- error: error.message,
413
- isRetryable
414
- }, 'Upload message body failed, no more retries');
415
- throw error;
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
- const delay = Math.min(
419
- retryDelay * Math.pow(2, attempt),
420
- this.settings.PROXY_OBJECT_REQUEST_MAX_RETRY_DELAY
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
- await new Promise(resolve => setTimeout(resolve, delay));
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
- // Ensure connection is still valid before retry
432
- if (!this.isConnected()) {
433
- log.info('Reconnecting before retry...');
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
- return new Promise((resolve, reject) => {
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
- return reject(new Error(`Failed to send message, status code: ${headers[HTTP2_HEADER_STATUS]}`));
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
- return new Promise((resolve, reject) => {
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
- return reject(new Error(`Failed to finish processing message, status code: ${headers[HTTP2_HEADER_STATUS]}`));
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
- postMessageStream.on('error', reject);
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
@@ -1,7 +1,7 @@
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-dev5",
4
+ "version": "3.0.0-dev6",
5
5
  "main": "run.js",
6
6
  "scripts": {
7
7
  "build": "tsc",