elasticio-sailor-nodejs 3.0.0-sailor-proxy-dev1 → 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/lib/proxy-client.js +37 -5
- package/lib/sailor.js +7 -5
- package/package.json +1 -1
- package/run.js +20 -16
- package/run.local.js +3 -1
- package/mise.toml +0 -2
package/lib/proxy-client.js
CHANGED
|
@@ -12,7 +12,8 @@ const {
|
|
|
12
12
|
HTTP2_HEADER_PATH,
|
|
13
13
|
HTTP2_HEADER_METHOD,
|
|
14
14
|
HTTP2_HEADER_AUTHORIZATION,
|
|
15
|
-
HTTP2_HEADER_STATUS
|
|
15
|
+
HTTP2_HEADER_STATUS,
|
|
16
|
+
NGHTTP2_NO_ERROR
|
|
16
17
|
} = http2.constants;
|
|
17
18
|
|
|
18
19
|
const HEADER_ROUTING_KEY = 'x-eio-routing-key';
|
|
@@ -29,10 +30,12 @@ class ProxyClient {
|
|
|
29
30
|
this.settings = settings;
|
|
30
31
|
this._encryptor = new Encryptor(this.settings.MESSAGE_CRYPTO_PASSWORD, this.settings.MESSAGE_CRYPTO_IV);
|
|
31
32
|
this.closed = true;
|
|
33
|
+
this.listeningForMessages = true;
|
|
32
34
|
this.clientSession = null;
|
|
33
35
|
this.reconnecting = false;
|
|
34
36
|
this.reconnectAttempts = 0;
|
|
35
37
|
this.reconnectTimer = null;
|
|
38
|
+
this.getMessageStreams = new Set();
|
|
36
39
|
|
|
37
40
|
const username = settings.API_USERNAME;
|
|
38
41
|
const password = settings.API_KEY;
|
|
@@ -100,24 +103,27 @@ class ProxyClient {
|
|
|
100
103
|
|
|
101
104
|
// Handle connection close
|
|
102
105
|
this.clientSession.on('close', () => {
|
|
103
|
-
log.
|
|
106
|
+
log.debug({ closed: this.closed, reconnecting: this.reconnecting }, 'HTTP2 session closed');
|
|
104
107
|
if (!this.closed && !this.reconnecting) {
|
|
108
|
+
log.warn('HTTP2 session closed unexpectedly, initiating reconnection');
|
|
105
109
|
this._handleDisconnection('close');
|
|
106
110
|
}
|
|
107
111
|
});
|
|
108
112
|
|
|
109
113
|
// Handle GOAWAY frames (server-initiated shutdown)
|
|
110
114
|
this.clientSession.on('goaway', (errorCode, lastStreamID, opaqueData) => {
|
|
111
|
-
log.
|
|
115
|
+
log.debug({ errorCode, lastStreamID, closed: this.closed }, 'Received GOAWAY from server');
|
|
112
116
|
if (!this.closed) {
|
|
117
|
+
log.warn('Received GOAWAY frame from server, initiating reconnection');
|
|
113
118
|
this._handleDisconnection('goaway', { errorCode, lastStreamID });
|
|
114
119
|
}
|
|
115
120
|
});
|
|
116
121
|
|
|
117
122
|
// Handle timeout
|
|
118
123
|
this.clientSession.on('timeout', () => {
|
|
119
|
-
log.
|
|
124
|
+
log.debug({ closed: this.closed }, 'HTTP2 session timeout');
|
|
120
125
|
if (!this.closed) {
|
|
126
|
+
log.warn('HTTP2 session timeout, initiating reconnection');
|
|
121
127
|
this._handleDisconnection('timeout');
|
|
122
128
|
}
|
|
123
129
|
});
|
|
@@ -192,11 +198,13 @@ class ProxyClient {
|
|
|
192
198
|
|
|
193
199
|
// Clear any pending reconnection timers
|
|
194
200
|
if (this.reconnectTimer) {
|
|
201
|
+
log.debug('Clearing pending reconnection timer');
|
|
195
202
|
clearTimeout(this.reconnectTimer);
|
|
196
203
|
this.reconnectTimer = null;
|
|
197
204
|
}
|
|
198
205
|
|
|
199
206
|
return new Promise((resolve) => {
|
|
207
|
+
log.debug('Disconnecting from Sailor Proxy');
|
|
200
208
|
if (!this.clientSession || this.clientSession.destroyed) {
|
|
201
209
|
log.debug('Session already destroyed');
|
|
202
210
|
return resolve();
|
|
@@ -391,23 +399,27 @@ class ProxyClient {
|
|
|
391
399
|
}
|
|
392
400
|
|
|
393
401
|
async listenForMessages(messageHandler) {
|
|
394
|
-
while (
|
|
402
|
+
while (this.listeningForMessages) {
|
|
395
403
|
try {
|
|
404
|
+
log.debug('Starting to listen for messages from proxy');
|
|
396
405
|
await this._ensureConnection();
|
|
397
406
|
|
|
398
407
|
const stepId = this.settings.STEP_ID;
|
|
399
408
|
const prefetch = this.settings.PROXY_PREFETCH_SAILOR;
|
|
409
|
+
// TODO: When prefetch > 1, what if one message takes a long time to process - do we want to wait for it before requesting the next one?
|
|
400
410
|
await Promise.all(new Array(prefetch).fill().map(async () => {
|
|
401
411
|
const queryParams = new URLSearchParams({
|
|
402
412
|
stepId,
|
|
403
413
|
prefetch
|
|
404
414
|
}).toString();
|
|
405
415
|
log.info({ stepId, prefetch }, 'Requesting message from proxy');
|
|
416
|
+
// TODO: what timeout is here? e.g. when flow is realtime - we might need to wait a long time...
|
|
406
417
|
const getMessageStream = this.clientSession.request({
|
|
407
418
|
[HTTP2_HEADER_PATH]: `/message?${queryParams}`,
|
|
408
419
|
[HTTP2_HEADER_METHOD]: 'GET',
|
|
409
420
|
[HTTP2_HEADER_AUTHORIZATION]: this.authHeader
|
|
410
421
|
});
|
|
422
|
+
this.getMessageStreams.add(getMessageStream);
|
|
411
423
|
|
|
412
424
|
const { headers, body } = await new Promise((resolve, reject) => {
|
|
413
425
|
getMessageStream.on('response', (headers, flags) => {
|
|
@@ -459,10 +471,30 @@ class ProxyClient {
|
|
|
459
471
|
log.debug('Currently reconnecting, will retry listening for messages after reconnection');
|
|
460
472
|
}
|
|
461
473
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
474
|
+
} finally {
|
|
475
|
+
log.debug('Cleaning up message streams');
|
|
476
|
+
this.getMessageStreams.clear();
|
|
462
477
|
}
|
|
463
478
|
}
|
|
464
479
|
}
|
|
465
480
|
|
|
481
|
+
async stopListeningForMessages() {
|
|
482
|
+
log.info('Stopping listening for messages');
|
|
483
|
+
await Promise.all(Array.from(this.getMessageStreams).map(stream => {
|
|
484
|
+
if (stream.closed || stream.destroyed) {
|
|
485
|
+
log.debug({ closed: stream.closed, destroyed: stream.destroyed }, 'Message stream is already closed or destroyed');
|
|
486
|
+
return Promise.resolve();
|
|
487
|
+
}
|
|
488
|
+
return new Promise((resolve) => {
|
|
489
|
+
stream.close(NGHTTP2_NO_ERROR, () => {
|
|
490
|
+
log.debug('Closed message stream');
|
|
491
|
+
resolve();
|
|
492
|
+
});
|
|
493
|
+
});
|
|
494
|
+
}));
|
|
495
|
+
this.listeningForMessages = false;
|
|
496
|
+
}
|
|
497
|
+
|
|
466
498
|
async sendMessage({
|
|
467
499
|
incomingMessageId,
|
|
468
500
|
type,
|
package/lib/sailor.js
CHANGED
|
@@ -80,7 +80,6 @@ class Sailor {
|
|
|
80
80
|
}
|
|
81
81
|
|
|
82
82
|
async disconnect() {
|
|
83
|
-
// TODO: delete if not needed (currently used only in old tests)
|
|
84
83
|
log.debug('Disconnecting, %s messages in processing', this.messagesCount);
|
|
85
84
|
return this.proxyClient.disconnect();
|
|
86
85
|
}
|
|
@@ -171,10 +170,13 @@ class Sailor {
|
|
|
171
170
|
|
|
172
171
|
async processMessageAndMaybeShutdownCallback(headers, body) {
|
|
173
172
|
try {
|
|
174
|
-
|
|
173
|
+
await this.processMessage(headers, body);
|
|
175
174
|
} catch (e) {
|
|
176
175
|
log.error(e, 'Something very bad happened during message processing');
|
|
177
176
|
} finally {
|
|
177
|
+
log.debug({
|
|
178
|
+
messagesCount: this.messagesCount
|
|
179
|
+
}, 'Finished processing message, checking if shutdownCallback should be called');
|
|
178
180
|
if (this.shutdownCallback) {
|
|
179
181
|
if (this.messagesCount === 0) {
|
|
180
182
|
// there is no another processMessage invocation, so it's time to call shutdownCallback
|
|
@@ -195,7 +197,7 @@ class Sailor {
|
|
|
195
197
|
return new Promise(resolve => this.shutdownCallback = resolve);
|
|
196
198
|
}
|
|
197
199
|
|
|
198
|
-
await this.proxyClient.
|
|
200
|
+
await this.proxyClient.stopListeningForMessages();
|
|
199
201
|
if (this.messagesCount === 0) {
|
|
200
202
|
// there is no unfinished processMessage invocation, let's just resolve scheduleShutdown now
|
|
201
203
|
log.debug('scheduleShutdown – about to shutdown immediately');
|
|
@@ -443,7 +445,7 @@ class Sailor {
|
|
|
443
445
|
}
|
|
444
446
|
}
|
|
445
447
|
|
|
446
|
-
function onEnd() {
|
|
448
|
+
async function onEnd() {
|
|
447
449
|
if (endWasEmitted) {
|
|
448
450
|
logger.warn({
|
|
449
451
|
messagesCount: that.messagesCount,
|
|
@@ -455,7 +457,7 @@ class Sailor {
|
|
|
455
457
|
|
|
456
458
|
endWasEmitted = true;
|
|
457
459
|
|
|
458
|
-
that.proxyClient.finishProcessing(
|
|
460
|
+
await that.proxyClient.finishProcessing(
|
|
459
461
|
incomingMessageHeaders,
|
|
460
462
|
taskExec.errorCount > 0
|
|
461
463
|
? MESSAGE_PROCESSING_STATUS.ERROR
|
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-sailor-proxy-
|
|
4
|
+
"version": "3.0.0-sailor-proxy-dev2",
|
|
5
5
|
"main": "run.js",
|
|
6
6
|
"scripts": {
|
|
7
7
|
"build": "tsc",
|
package/run.js
CHANGED
|
@@ -74,8 +74,10 @@ async function gracefulShutdown() {
|
|
|
74
74
|
logger.trace('Waited an init before graceful shutdown');
|
|
75
75
|
|
|
76
76
|
try {
|
|
77
|
-
logger.info('
|
|
77
|
+
logger.info('Scheduling shutdown...');
|
|
78
78
|
await sailor.scheduleShutdown();
|
|
79
|
+
logger.info('Finished shutdown. Disconnecting...');
|
|
80
|
+
await sailor.disconnect();
|
|
79
81
|
logger.info('Successfully disconnected');
|
|
80
82
|
process.exit();
|
|
81
83
|
} catch (err) {
|
|
@@ -88,7 +90,6 @@ async function run(settings, ipc) {
|
|
|
88
90
|
prepareSandbox();
|
|
89
91
|
try {
|
|
90
92
|
await putOutToSea(settings, ipc);
|
|
91
|
-
logger.info('Fully initialized and waiting for messages');
|
|
92
93
|
} catch (e) {
|
|
93
94
|
if (sailor && !sailor.isConnected()) {
|
|
94
95
|
await sailor.reportError(e);
|
|
@@ -97,6 +98,21 @@ async function run(settings, ipc) {
|
|
|
97
98
|
}
|
|
98
99
|
}
|
|
99
100
|
|
|
101
|
+
function addProcessListeners() {
|
|
102
|
+
process.on('SIGTERM', function onSigterm() {
|
|
103
|
+
logger.info('Received SIGTERM');
|
|
104
|
+
gracefulShutdown();
|
|
105
|
+
});
|
|
106
|
+
|
|
107
|
+
process.on('SIGINT', function onSigint() {
|
|
108
|
+
logger.info('Received SIGINT');
|
|
109
|
+
gracefulShutdown();
|
|
110
|
+
});
|
|
111
|
+
|
|
112
|
+
process.on('uncaughtException', logger.criticalErrorAndExit.bind(logger, 'process.uncaughtException'));
|
|
113
|
+
process.on('unhandledRejection', (err) => logger.error(err, 'process.unhandledRejection'));
|
|
114
|
+
}
|
|
115
|
+
|
|
100
116
|
exports.__test__ = {
|
|
101
117
|
disconnectOnly: function disconnectOnly() {
|
|
102
118
|
if (!disconnectRequired) {
|
|
@@ -110,22 +126,10 @@ exports.__test__ = {
|
|
|
110
126
|
};
|
|
111
127
|
exports.run = run;
|
|
112
128
|
exports.putOutToSea = putOutToSea;
|
|
129
|
+
exports.addProcessListeners = addProcessListeners;
|
|
113
130
|
|
|
114
131
|
if (require.main === module || process.mainModule.filename === __filename) {
|
|
115
|
-
|
|
116
|
-
logger.info('Received SIGTERM');
|
|
117
|
-
gracefulShutdown();
|
|
118
|
-
});
|
|
119
|
-
|
|
120
|
-
process.on('SIGINT', function onSigint() {
|
|
121
|
-
logger.info('Received SIGINT');
|
|
122
|
-
gracefulShutdown();
|
|
123
|
-
});
|
|
124
|
-
|
|
125
|
-
process.on('uncaughtException', logger.criticalErrorAndExit.bind(logger, 'process.uncaughtException'));
|
|
126
|
-
process.on('unhandledRejection', (err) => logger.error(err, 'process.unhandledRejection'));
|
|
127
|
-
|
|
132
|
+
addProcessListeners();
|
|
128
133
|
const ipc = new IPC();
|
|
129
|
-
|
|
130
134
|
run(settings.readFrom(process.env), ipc);
|
|
131
135
|
}
|
package/run.local.js
CHANGED
|
@@ -8,7 +8,9 @@ function setEnvVars() {
|
|
|
8
8
|
setEnvVars();
|
|
9
9
|
|
|
10
10
|
const { IPC } = require('./lib/ipc');
|
|
11
|
-
const { run } = require('./run');
|
|
11
|
+
const { addProcessListeners, run } = require('./run');
|
|
12
12
|
const settings = require('./lib/settings.js');
|
|
13
13
|
const ipc = new IPC();
|
|
14
|
+
|
|
15
|
+
addProcessListeners();
|
|
14
16
|
run(settings.readFrom(process.env), ipc);
|
package/mise.toml
DELETED