@friggframework/core 2.0.0--canary.578.3f8e78e.0 → 2.0.0--canary.579.4f65577.0
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/core/Worker.js +0 -36
- package/core/create-handler.js +0 -64
- package/handlers/backend-utils.js +6 -44
- package/modules/requester/requester.js +64 -4
- package/package.json +5 -5
- package/queues/queuer-util.js +3 -80
package/core/Worker.js
CHANGED
|
@@ -20,45 +20,15 @@ class Worker {
|
|
|
20
20
|
const records = get(params, 'Records');
|
|
21
21
|
const batchItemFailures = [];
|
|
22
22
|
|
|
23
|
-
console.log(
|
|
24
|
-
`[Worker] run: processing ${records.length} record(s)`
|
|
25
|
-
);
|
|
26
|
-
|
|
27
23
|
for (const record of records) {
|
|
28
|
-
// Log record entry with SQS-provided attributes useful for tracing
|
|
29
|
-
// delivery history (ApproximateReceiveCount for retries, etc.).
|
|
30
|
-
let parsedEvent;
|
|
31
|
-
try {
|
|
32
|
-
parsedEvent = JSON.parse(record.body)?.event;
|
|
33
|
-
} catch {
|
|
34
|
-
parsedEvent = undefined;
|
|
35
|
-
}
|
|
36
|
-
console.log(`[Worker] record begin`, {
|
|
37
|
-
messageId: record.messageId,
|
|
38
|
-
event: parsedEvent,
|
|
39
|
-
receiveCount: record.attributes?.ApproximateReceiveCount,
|
|
40
|
-
});
|
|
41
|
-
|
|
42
24
|
try {
|
|
43
25
|
const runParams = JSON.parse(record.body);
|
|
44
26
|
this._validateParams(runParams);
|
|
45
27
|
await this._run(runParams, context);
|
|
46
|
-
console.log(`[Worker] record success`, {
|
|
47
|
-
messageId: record.messageId,
|
|
48
|
-
event: runParams?.event,
|
|
49
|
-
});
|
|
50
28
|
} catch (error) {
|
|
51
29
|
if (error.isHaltError) {
|
|
52
30
|
// HaltError means "discard this message, don't retry".
|
|
53
31
|
// Treat as success so SQS deletes it from the queue.
|
|
54
|
-
// Logged explicitly — silent discards made prod debugging
|
|
55
|
-
// extremely hard; keep this visible.
|
|
56
|
-
console.warn(`[Worker] record halted (discarded, no retry)`, {
|
|
57
|
-
messageId: record.messageId,
|
|
58
|
-
event: parsedEvent,
|
|
59
|
-
reason: error.message,
|
|
60
|
-
statusCode: error.statusCode,
|
|
61
|
-
});
|
|
62
32
|
continue;
|
|
63
33
|
}
|
|
64
34
|
console.error(`[Worker] Failed to process record ${record.messageId}:`, error);
|
|
@@ -66,12 +36,6 @@ class Worker {
|
|
|
66
36
|
}
|
|
67
37
|
}
|
|
68
38
|
|
|
69
|
-
if (batchItemFailures.length > 0) {
|
|
70
|
-
console.warn(
|
|
71
|
-
`[Worker] run: returning ${batchItemFailures.length} batchItemFailure(s) of ${records.length}`
|
|
72
|
-
);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
39
|
return { batchItemFailures };
|
|
76
40
|
}
|
|
77
41
|
|
package/core/create-handler.js
CHANGED
|
@@ -5,45 +5,6 @@
|
|
|
5
5
|
const { initDebugLog, flushDebugLog } = require('../logs');
|
|
6
6
|
const { secretsToEnv } = require('./secrets-to-env');
|
|
7
7
|
|
|
8
|
-
// Best-effort extraction of correlation identifiers from a Lambda event.
|
|
9
|
-
// For SQS: pulls messageIds + parsed event/processId/integrationId from each
|
|
10
|
-
// record body. For HTTP: pulls method+path. Never throws.
|
|
11
|
-
const summarizeLambdaEvent = (event) => {
|
|
12
|
-
if (!event) return {};
|
|
13
|
-
if (Array.isArray(event.Records)) {
|
|
14
|
-
return {
|
|
15
|
-
source: 'sqs',
|
|
16
|
-
records: event.Records.map((r) => {
|
|
17
|
-
let parsed = {};
|
|
18
|
-
try {
|
|
19
|
-
const body = JSON.parse(r.body);
|
|
20
|
-
parsed = {
|
|
21
|
-
event: body?.event,
|
|
22
|
-
processId: body?.data?.processId,
|
|
23
|
-
integrationId: body?.data?.integrationId,
|
|
24
|
-
};
|
|
25
|
-
} catch {
|
|
26
|
-
// ignore unparseable bodies
|
|
27
|
-
}
|
|
28
|
-
return {
|
|
29
|
-
messageId: r.messageId,
|
|
30
|
-
receiveCount: r.attributes?.ApproximateReceiveCount,
|
|
31
|
-
...parsed,
|
|
32
|
-
};
|
|
33
|
-
}),
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
if (event.httpMethod || event.requestContext?.http) {
|
|
37
|
-
return {
|
|
38
|
-
source: 'http',
|
|
39
|
-
method:
|
|
40
|
-
event.httpMethod || event.requestContext?.http?.method,
|
|
41
|
-
path: event.path || event.rawPath,
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
return { source: 'other' };
|
|
45
|
-
};
|
|
46
|
-
|
|
47
8
|
const createHandler = (optionByName = {}) => {
|
|
48
9
|
const {
|
|
49
10
|
eventName = 'Event',
|
|
@@ -56,18 +17,7 @@ const createHandler = (optionByName = {}) => {
|
|
|
56
17
|
}
|
|
57
18
|
|
|
58
19
|
return async (event, context) => {
|
|
59
|
-
const eventSummary = summarizeLambdaEvent(event);
|
|
60
|
-
|
|
61
20
|
try {
|
|
62
|
-
console.info(
|
|
63
|
-
`[createHandler] ${eventName}: handler entry`,
|
|
64
|
-
{
|
|
65
|
-
eventName,
|
|
66
|
-
awsRequestId: context?.awsRequestId,
|
|
67
|
-
...eventSummary,
|
|
68
|
-
}
|
|
69
|
-
);
|
|
70
|
-
|
|
71
21
|
initDebugLog(eventName, event);
|
|
72
22
|
|
|
73
23
|
const requestMethod = event.httpMethod;
|
|
@@ -112,21 +62,7 @@ const createHandler = (optionByName = {}) => {
|
|
|
112
62
|
// Handle server-to-server responses.
|
|
113
63
|
|
|
114
64
|
// Halt errors are logged but suceed and won't be retried.
|
|
115
|
-
// Log explicitly — silent suppression here previously made stuck
|
|
116
|
-
// messages invisible to observability tooling. Include
|
|
117
|
-
// eventSummary so operators can correlate across concurrent
|
|
118
|
-
// invocations (processId / messageIds / HTTP path).
|
|
119
65
|
if (error.isHaltError === true) {
|
|
120
|
-
console.warn(
|
|
121
|
-
`[createHandler] ${eventName}: halt error suppressed (no retry)`,
|
|
122
|
-
{
|
|
123
|
-
eventName,
|
|
124
|
-
errorName: error.name,
|
|
125
|
-
errorMessage: error.message,
|
|
126
|
-
statusCode: error.statusCode,
|
|
127
|
-
...eventSummary,
|
|
128
|
-
}
|
|
129
|
-
);
|
|
130
66
|
return;
|
|
131
67
|
}
|
|
132
68
|
|
|
@@ -141,17 +141,8 @@ const loadIntegrationForProcess = async (processId, integrationClass) => {
|
|
|
141
141
|
};
|
|
142
142
|
|
|
143
143
|
const createQueueWorker = (integrationClass) => {
|
|
144
|
-
const integrationName = integrationClass.Definition.name;
|
|
145
|
-
|
|
146
144
|
class QueueWorker extends Worker {
|
|
147
145
|
async _run(params, context) {
|
|
148
|
-
const logCtx = {
|
|
149
|
-
integration: integrationName,
|
|
150
|
-
event: params.event,
|
|
151
|
-
processId: params.data?.processId,
|
|
152
|
-
integrationId: params.data?.integrationId,
|
|
153
|
-
};
|
|
154
|
-
|
|
155
146
|
try {
|
|
156
147
|
let integrationInstance;
|
|
157
148
|
|
|
@@ -159,46 +150,29 @@ const createQueueWorker = (integrationClass) => {
|
|
|
159
150
|
// then integrationId (for ANY event type that needs hydration),
|
|
160
151
|
// fallback to unhydrated instance
|
|
161
152
|
if (params.data?.processId) {
|
|
162
|
-
console.log(
|
|
163
|
-
`[QueueWorker] hydrating by processId`,
|
|
164
|
-
logCtx
|
|
165
|
-
);
|
|
166
153
|
integrationInstance = await loadIntegrationForProcess(
|
|
167
154
|
params.data.processId,
|
|
168
155
|
integrationClass
|
|
169
156
|
);
|
|
170
|
-
console.log(`[QueueWorker] hydrated`, {
|
|
171
|
-
...logCtx,
|
|
172
|
-
integrationStatus: integrationInstance?.status,
|
|
173
|
-
hydratedIntegrationId: integrationInstance?.id,
|
|
174
|
-
});
|
|
175
157
|
if (['DISABLED', 'ERROR'].includes(integrationInstance?.status)) {
|
|
176
158
|
console.warn(
|
|
177
|
-
`[${
|
|
159
|
+
`[${integrationClass.Definition.name}] Integration for process ${params.data.processId} is ${integrationInstance.status}. Discarding ${params.event} message.`
|
|
178
160
|
);
|
|
179
161
|
return;
|
|
180
162
|
}
|
|
181
163
|
} else if (params.data?.integrationId) {
|
|
182
|
-
console.log(
|
|
183
|
-
`[QueueWorker] hydrating by integrationId`,
|
|
184
|
-
logCtx
|
|
185
|
-
);
|
|
186
164
|
integrationInstance = await loadIntegrationForWebhook(
|
|
187
165
|
params.data.integrationId
|
|
188
166
|
);
|
|
189
167
|
if (!integrationInstance) {
|
|
190
168
|
console.warn(
|
|
191
|
-
`[${
|
|
169
|
+
`[${integrationClass.Definition.name}] Integration ${params.data.integrationId} no longer exists. Discarding ${params.event} message.`
|
|
192
170
|
);
|
|
193
171
|
return;
|
|
194
172
|
}
|
|
195
|
-
console.log(`[QueueWorker] hydrated`, {
|
|
196
|
-
...logCtx,
|
|
197
|
-
integrationStatus: integrationInstance?.status,
|
|
198
|
-
});
|
|
199
173
|
if (['DISABLED', 'ERROR'].includes(integrationInstance.status)) {
|
|
200
174
|
console.warn(
|
|
201
|
-
`[${
|
|
175
|
+
`[${integrationClass.Definition.name}] Integration ${params.data.integrationId} is ${integrationInstance.status}. Discarding ${params.event} message.`
|
|
202
176
|
);
|
|
203
177
|
return;
|
|
204
178
|
}
|
|
@@ -207,10 +181,6 @@ const createQueueWorker = (integrationClass) => {
|
|
|
207
181
|
// There will be cases where we need to use helpers that the api modules can export.
|
|
208
182
|
// Like for HubSpot, the answer is to do a reverse lookup for the integration by the entity external ID (HubSpot Portal ID),
|
|
209
183
|
// and then you'll have the integration ID available to hydrate from.
|
|
210
|
-
console.log(
|
|
211
|
-
`[QueueWorker] no processId/integrationId — running dry instance`,
|
|
212
|
-
logCtx
|
|
213
|
-
);
|
|
214
184
|
integrationInstance = new integrationClass();
|
|
215
185
|
}
|
|
216
186
|
|
|
@@ -218,17 +188,14 @@ const createQueueWorker = (integrationClass) => {
|
|
|
218
188
|
integrationInstance
|
|
219
189
|
);
|
|
220
190
|
|
|
221
|
-
|
|
222
|
-
const result = await dispatcher.dispatchJob({
|
|
191
|
+
return await dispatcher.dispatchJob({
|
|
223
192
|
event: params.event,
|
|
224
193
|
data: params.data,
|
|
225
194
|
context: context,
|
|
226
195
|
});
|
|
227
|
-
console.log(`[QueueWorker] ${params.event} dispatched ok`, logCtx);
|
|
228
|
-
return result;
|
|
229
196
|
} catch (error) {
|
|
230
197
|
console.error(
|
|
231
|
-
`Error in ${params.event} for ${
|
|
198
|
+
`Error in ${params.event} for ${integrationClass.Definition.name}:`,
|
|
232
199
|
error
|
|
233
200
|
);
|
|
234
201
|
|
|
@@ -240,12 +207,7 @@ const createQueueWorker = (integrationClass) => {
|
|
|
240
207
|
if (status && status >= 400 && status < 500 && status !== 408 && status !== 429) {
|
|
241
208
|
error.isHaltError = true;
|
|
242
209
|
console.warn(
|
|
243
|
-
`[${
|
|
244
|
-
{
|
|
245
|
-
...logCtx,
|
|
246
|
-
errorName: error.name,
|
|
247
|
-
errorMessage: error.message,
|
|
248
|
-
}
|
|
210
|
+
`[${integrationClass.Definition.name}] Permanent ${status} error for ${params.event} — message will be discarded (no retry)`
|
|
249
211
|
);
|
|
250
212
|
}
|
|
251
213
|
|
|
@@ -3,6 +3,8 @@ const { Delegate } = require('../../core');
|
|
|
3
3
|
const { FetchError } = require('../../errors');
|
|
4
4
|
const { get } = require('../../assertions');
|
|
5
5
|
|
|
6
|
+
const DEFAULT_REQUEST_TIMEOUT_MS = 60_000;
|
|
7
|
+
|
|
6
8
|
class Requester extends Delegate {
|
|
7
9
|
constructor(params) {
|
|
8
10
|
super(params);
|
|
@@ -13,6 +15,30 @@ class Requester extends Delegate {
|
|
|
13
15
|
this.delegateTypes.push(this.DLGT_INVALID_AUTH);
|
|
14
16
|
this.agent = get(params, 'agent', null);
|
|
15
17
|
|
|
18
|
+
// Per-attempt HTTP timeout. Without this the framework called fetch()
|
|
19
|
+
// with no AbortController and no timeout — a silently-hung TCP
|
|
20
|
+
// connection (server accepts but never responds) blocked the calling
|
|
21
|
+
// promise forever, cascading into stalled batches, stalled syncs,
|
|
22
|
+
// and worker-lambda timeouts.
|
|
23
|
+
//
|
|
24
|
+
// Configuration precedence:
|
|
25
|
+
// 1. Instance param: new Requester({ requestTimeoutMs: 30_000 })
|
|
26
|
+
// 2. Class static: static requestTimeoutMs = 30_000
|
|
27
|
+
// 3. Default: DEFAULT_REQUEST_TIMEOUT_MS (60s)
|
|
28
|
+
//
|
|
29
|
+
// Pass 0 (or null) to disable the timeout entirely — reserved for
|
|
30
|
+
// test doubles and documented long-running endpoints.
|
|
31
|
+
// Intentionally NOT using `get(params, ...)` here — the Frigg
|
|
32
|
+
// `get` helper throws RequiredPropertyError if the key is missing
|
|
33
|
+
// and no default is provided, which would collide with the fall-
|
|
34
|
+
// through to the class-level static override.
|
|
35
|
+
const instanceTimeout = params?.requestTimeoutMs;
|
|
36
|
+
this.requestTimeoutMs =
|
|
37
|
+
instanceTimeout !== undefined && instanceTimeout !== null
|
|
38
|
+
? instanceTimeout
|
|
39
|
+
: this.constructor.requestTimeoutMs ??
|
|
40
|
+
DEFAULT_REQUEST_TIMEOUT_MS;
|
|
41
|
+
|
|
16
42
|
// Allow passing in the fetch function
|
|
17
43
|
// Instance methods can use this.fetch without differentiating
|
|
18
44
|
this.fetch = get(params, 'fetch', fetch);
|
|
@@ -48,20 +74,54 @@ class Requester extends Delegate {
|
|
|
48
74
|
|
|
49
75
|
if (this.agent) options.agent = this.agent;
|
|
50
76
|
|
|
77
|
+
// Per-attempt timeout — fresh AbortController per call so the retry
|
|
78
|
+
// recursion (with its own backoff sleeps) always gets a clean
|
|
79
|
+
// signal. Timer is cleared in the finally block regardless of
|
|
80
|
+
// outcome.
|
|
81
|
+
const timeoutMs = this.requestTimeoutMs;
|
|
82
|
+
const controller = timeoutMs > 0 ? new AbortController() : null;
|
|
83
|
+
const timeoutHandle = controller
|
|
84
|
+
? setTimeout(() => controller.abort(), timeoutMs)
|
|
85
|
+
: null;
|
|
86
|
+
const fetchOptions = controller
|
|
87
|
+
? { ...options, signal: controller.signal }
|
|
88
|
+
: options;
|
|
89
|
+
|
|
51
90
|
let response;
|
|
52
91
|
try {
|
|
53
|
-
response = await this.fetch(encodedUrl,
|
|
92
|
+
response = await this.fetch(encodedUrl, fetchOptions);
|
|
54
93
|
} catch (e) {
|
|
55
|
-
|
|
94
|
+
// AbortController fires AbortError (name) / ETIMEDOUT-shaped
|
|
95
|
+
// errors (type on node-fetch) when we hit the timeout. No
|
|
96
|
+
// retry on timeout: a slow endpoint is a downstream problem,
|
|
97
|
+
// and each retry would wait another `timeoutMs` before giving
|
|
98
|
+
// up — amplifying the hang into a per-record multi-minute
|
|
99
|
+
// stall at batch scale.
|
|
100
|
+
const isTimeout =
|
|
101
|
+
e?.name === 'AbortError' || e?.type === 'aborted';
|
|
102
|
+
if (e?.code === 'ECONNRESET' && i < this.backOff.length) {
|
|
56
103
|
const delay = this.backOff[i] * 1000;
|
|
57
104
|
await new Promise((resolve) => setTimeout(resolve, delay));
|
|
58
105
|
return this._request(url, options, i + 1);
|
|
59
106
|
}
|
|
60
|
-
|
|
107
|
+
const fetchError = await FetchError.create({
|
|
61
108
|
resource: encodedUrl,
|
|
62
109
|
init: options,
|
|
63
|
-
responseBody:
|
|
110
|
+
responseBody: isTimeout
|
|
111
|
+
? `Request timed out after ${timeoutMs}ms`
|
|
112
|
+
: e,
|
|
64
113
|
});
|
|
114
|
+
if (isTimeout) {
|
|
115
|
+
// Flag + machine-readable fields so callers can
|
|
116
|
+
// distinguish a timeout from a generic network error
|
|
117
|
+
// without parsing the message (which FetchError
|
|
118
|
+
// sanitizes outside of STAGE=dev).
|
|
119
|
+
fetchError.isTimeout = true;
|
|
120
|
+
fetchError.timeoutMs = timeoutMs;
|
|
121
|
+
}
|
|
122
|
+
throw fetchError;
|
|
123
|
+
} finally {
|
|
124
|
+
if (timeoutHandle) clearTimeout(timeoutHandle);
|
|
65
125
|
}
|
|
66
126
|
const { status } = response;
|
|
67
127
|
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@friggframework/core",
|
|
3
3
|
"prettier": "@friggframework/prettier-config",
|
|
4
|
-
"version": "2.0.0--canary.
|
|
4
|
+
"version": "2.0.0--canary.579.4f65577.0",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"@aws-sdk/client-apigatewaymanagementapi": "^3.588.0",
|
|
7
7
|
"@aws-sdk/client-kms": "^3.588.0",
|
|
@@ -38,9 +38,9 @@
|
|
|
38
38
|
}
|
|
39
39
|
},
|
|
40
40
|
"devDependencies": {
|
|
41
|
-
"@friggframework/eslint-config": "2.0.0--canary.
|
|
42
|
-
"@friggframework/prettier-config": "2.0.0--canary.
|
|
43
|
-
"@friggframework/test": "2.0.0--canary.
|
|
41
|
+
"@friggframework/eslint-config": "2.0.0--canary.579.4f65577.0",
|
|
42
|
+
"@friggframework/prettier-config": "2.0.0--canary.579.4f65577.0",
|
|
43
|
+
"@friggframework/test": "2.0.0--canary.579.4f65577.0",
|
|
44
44
|
"@prisma/client": "^6.17.0",
|
|
45
45
|
"@types/lodash": "4.17.15",
|
|
46
46
|
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
@@ -80,5 +80,5 @@
|
|
|
80
80
|
"publishConfig": {
|
|
81
81
|
"access": "public"
|
|
82
82
|
},
|
|
83
|
-
"gitHead": "
|
|
83
|
+
"gitHead": "4f65577ef61f82fc02d25d22a92ffa851c179676"
|
|
84
84
|
}
|
package/queues/queuer-util.js
CHANGED
|
@@ -18,88 +18,13 @@ const awsConfigOptions = () => {
|
|
|
18
18
|
|
|
19
19
|
const sqs = new SQSClient(awsConfigOptions());
|
|
20
20
|
|
|
21
|
-
// Best-effort extraction of the logical event/processId/integrationId from a
|
|
22
|
-
// JSON message body. Used only for log correlation — never throws.
|
|
23
|
-
const summarizeMessageBody = (bodyStr) => {
|
|
24
|
-
try {
|
|
25
|
-
const parsed = JSON.parse(bodyStr);
|
|
26
|
-
return {
|
|
27
|
-
event: parsed?.event,
|
|
28
|
-
processId: parsed?.data?.processId,
|
|
29
|
-
integrationId: parsed?.data?.integrationId,
|
|
30
|
-
};
|
|
31
|
-
} catch {
|
|
32
|
-
return {};
|
|
33
|
-
}
|
|
34
|
-
};
|
|
35
|
-
|
|
36
|
-
// Inspect SendMessageBatchResult for partial failures and log them.
|
|
37
|
-
// AWS SendMessageBatch can succeed at the HTTP level while individual entries
|
|
38
|
-
// are rejected (KMS errors, per-entry throttling, service errors). Callers that
|
|
39
|
-
// don't inspect result.Failed silently lose those messages. This logs the
|
|
40
|
-
// details — including the logical event/processId of the failed entry — so
|
|
41
|
-
// the loss is visible and correlatable in CloudWatch.
|
|
42
|
-
const inspectBatchResult = (result, queueUrl, buffer) => {
|
|
43
|
-
const bufferSize = buffer.length;
|
|
44
|
-
const failedCount = result?.Failed?.length ?? 0;
|
|
45
|
-
const successCount = result?.Successful?.length ?? 0;
|
|
46
|
-
|
|
47
|
-
// Index buffer by Id so we can attach event/processId to failures.
|
|
48
|
-
const bufferById = new Map(buffer.map((b) => [b.Id, b]));
|
|
49
|
-
|
|
50
|
-
if (failedCount > 0) {
|
|
51
|
-
console.error(
|
|
52
|
-
`[QueuerUtil] SendMessageBatch partial failure: ${failedCount}/${bufferSize} failed`,
|
|
53
|
-
{
|
|
54
|
-
queueUrl,
|
|
55
|
-
bufferSize,
|
|
56
|
-
successCount,
|
|
57
|
-
failedCount,
|
|
58
|
-
failed: result.Failed.map((f) => {
|
|
59
|
-
const bufEntry = bufferById.get(f.Id);
|
|
60
|
-
const summary = bufEntry
|
|
61
|
-
? summarizeMessageBody(bufEntry.MessageBody)
|
|
62
|
-
: {};
|
|
63
|
-
return {
|
|
64
|
-
Id: f.Id,
|
|
65
|
-
Code: f.Code,
|
|
66
|
-
SenderFault: f.SenderFault,
|
|
67
|
-
Message: f.Message,
|
|
68
|
-
...summary,
|
|
69
|
-
};
|
|
70
|
-
}),
|
|
71
|
-
}
|
|
72
|
-
);
|
|
73
|
-
} else if (successCount > 0) {
|
|
74
|
-
// Include a compact per-entry summary so operators can correlate
|
|
75
|
-
// "which send contained which logical message" during incident triage.
|
|
76
|
-
const entries = result.Successful.map((s) => {
|
|
77
|
-
const bufEntry = bufferById.get(s.Id);
|
|
78
|
-
const summary = bufEntry
|
|
79
|
-
? summarizeMessageBody(bufEntry.MessageBody)
|
|
80
|
-
: {};
|
|
81
|
-
return { MessageId: s.MessageId, ...summary };
|
|
82
|
-
});
|
|
83
|
-
console.log(
|
|
84
|
-
`[QueuerUtil] SendMessageBatch ok: ${successCount}/${bufferSize} to ${queueUrl}`,
|
|
85
|
-
{ entries }
|
|
86
|
-
);
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
return result;
|
|
90
|
-
};
|
|
91
|
-
|
|
92
21
|
const QueuerUtil = {
|
|
93
22
|
send: async (message, queueUrl) => {
|
|
94
23
|
const command = new SendMessageCommand({
|
|
95
24
|
MessageBody: JSON.stringify(message),
|
|
96
25
|
QueueUrl: queueUrl,
|
|
97
26
|
});
|
|
98
|
-
|
|
99
|
-
console.log(
|
|
100
|
-
`[QueuerUtil] SendMessage ok: MessageId=${result?.MessageId} to ${queueUrl}`
|
|
101
|
-
);
|
|
102
|
-
return result;
|
|
27
|
+
return sqs.send(command);
|
|
103
28
|
},
|
|
104
29
|
|
|
105
30
|
batchSend: async (entries = [], queueUrl) => {
|
|
@@ -117,8 +42,7 @@ const QueuerUtil = {
|
|
|
117
42
|
Entries: buffer,
|
|
118
43
|
QueueUrl: queueUrl,
|
|
119
44
|
});
|
|
120
|
-
|
|
121
|
-
inspectBatchResult(result, queueUrl, buffer);
|
|
45
|
+
await sqs.send(command);
|
|
122
46
|
// Purge the buffer
|
|
123
47
|
buffer.splice(0, buffer.length);
|
|
124
48
|
}
|
|
@@ -130,8 +54,7 @@ const QueuerUtil = {
|
|
|
130
54
|
Entries: buffer,
|
|
131
55
|
QueueUrl: queueUrl,
|
|
132
56
|
});
|
|
133
|
-
|
|
134
|
-
return inspectBatchResult(result, queueUrl, buffer);
|
|
57
|
+
return sqs.send(command);
|
|
135
58
|
}
|
|
136
59
|
|
|
137
60
|
// If we're exact... just return an empty object for now
|