@message-queue-toolkit/core 24.2.0 → 25.1.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/README.md +375 -25
- package/dist/events/DomainEventEmitter.js +1 -1
- package/dist/events/DomainEventEmitter.js.map +1 -1
- package/dist/index.d.ts +6 -3
- package/dist/index.js +4 -2
- package/dist/index.js.map +1 -1
- package/dist/payload-store/JsonStreamStringifySerializer.d.ts +1 -1
- package/dist/queues/AbstractQueueService.d.ts +15 -3
- package/dist/queues/AbstractQueueService.js +51 -17
- package/dist/queues/AbstractQueueService.js.map +1 -1
- package/dist/queues/HandlerContainer.d.ts +36 -11
- package/dist/queues/HandlerContainer.js +69 -21
- package/dist/queues/HandlerContainer.js.map +1 -1
- package/dist/queues/HandlerSpy.d.ts +26 -3
- package/dist/queues/HandlerSpy.js +40 -8
- package/dist/queues/HandlerSpy.js.map +1 -1
- package/dist/queues/MessageSchemaContainer.d.ts +52 -6
- package/dist/queues/MessageSchemaContainer.js +126 -18
- package/dist/queues/MessageSchemaContainer.js.map +1 -1
- package/dist/queues/MessageTypeResolver.d.ts +154 -0
- package/dist/queues/MessageTypeResolver.js +82 -0
- package/dist/queues/MessageTypeResolver.js.map +1 -0
- package/dist/types/MessageQueueTypes.d.ts +2 -1
- package/dist/types/queueOptionsTypes.d.ts +148 -3
- package/dist/types/queueOptionsTypes.js +16 -1
- package/dist/types/queueOptionsTypes.js.map +1 -1
- package/dist/utils/startupResourcePollingUtils.d.ts +59 -0
- package/dist/utils/startupResourcePollingUtils.js +199 -0
- package/dist/utils/startupResourcePollingUtils.js.map +1 -0
- package/package.json +5 -4
|
@@ -4,6 +4,7 @@ import type { MessageDeduplicationConfig } from '../message-deduplication/messag
|
|
|
4
4
|
import type { PayloadStoreConfig } from '../payload-store/payloadStoreTypes.ts';
|
|
5
5
|
import type { MessageHandlerConfig } from '../queues/HandlerContainer.ts';
|
|
6
6
|
import type { HandlerSpy, HandlerSpyParams } from '../queues/HandlerSpy.ts';
|
|
7
|
+
import type { MessageTypeResolverConfig } from '../queues/MessageTypeResolver.ts';
|
|
7
8
|
import type { MessageProcessingResult, TransactionObservabilityManager } from './MessageQueueTypes.ts';
|
|
8
9
|
export type QueueDependencies = {
|
|
9
10
|
errorReporter: ErrorReporter;
|
|
@@ -16,9 +17,10 @@ export type ProcessedMessageMetadata<MessagePayloadSchemas extends object = obje
|
|
|
16
17
|
*/
|
|
17
18
|
messageId: string;
|
|
18
19
|
/**
|
|
19
|
-
* Message type
|
|
20
|
+
* Message type resolved by `messageTypeResolver`.
|
|
21
|
+
* May be undefined if messageTypeResolver is not configured.
|
|
20
22
|
*/
|
|
21
|
-
messageType
|
|
23
|
+
messageType?: string;
|
|
22
24
|
/**
|
|
23
25
|
* Processing result status
|
|
24
26
|
*/
|
|
@@ -60,8 +62,38 @@ export type QueueConsumerDependencies = {
|
|
|
60
62
|
consumerErrorResolver: ErrorResolver;
|
|
61
63
|
transactionObservabilityManager: TransactionObservabilityManager;
|
|
62
64
|
};
|
|
65
|
+
/**
|
|
66
|
+
* Common queue options for publishers and consumers.
|
|
67
|
+
*
|
|
68
|
+
* Message type resolution is configured via `messageTypeResolver`.
|
|
69
|
+
* At least one must be provided for routing to work (unless using a single handler).
|
|
70
|
+
*/
|
|
63
71
|
export type CommonQueueOptions = {
|
|
64
|
-
|
|
72
|
+
/**
|
|
73
|
+
* Configuration for resolving message types.
|
|
74
|
+
*
|
|
75
|
+
* Supports three modes:
|
|
76
|
+
* - `{ messageTypePath: string }` - field name at the root of the message
|
|
77
|
+
* - `{ literal: string }` - constant type for all messages
|
|
78
|
+
* - `{ resolver: fn }` - custom function for complex scenarios (e.g., extracting from attributes)
|
|
79
|
+
*
|
|
80
|
+
* @example
|
|
81
|
+
* // Field path - extracts type from message.type
|
|
82
|
+
* { messageTypeResolver: { messageTypePath: 'type' } }
|
|
83
|
+
*
|
|
84
|
+
* @example
|
|
85
|
+
* // Constant type - all messages treated as same type
|
|
86
|
+
* { messageTypeResolver: { literal: 'order.created' } }
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* // Custom resolver for Cloud Storage notifications via PubSub
|
|
90
|
+
* {
|
|
91
|
+
* messageTypeResolver: {
|
|
92
|
+
* resolver: ({ messageAttributes }) => messageAttributes?.eventType as string
|
|
93
|
+
* }
|
|
94
|
+
* }
|
|
95
|
+
*/
|
|
96
|
+
messageTypeResolver?: MessageTypeResolverConfig;
|
|
65
97
|
messageIdField?: string;
|
|
66
98
|
messageTimestampField?: string;
|
|
67
99
|
messageDeduplicationIdField?: string;
|
|
@@ -80,6 +112,119 @@ export type DeletionConfig = {
|
|
|
80
112
|
waitForConfirmation?: boolean;
|
|
81
113
|
forceDeleteInProduction?: boolean;
|
|
82
114
|
};
|
|
115
|
+
/**
|
|
116
|
+
* Symbol to indicate no timeout - polling will continue indefinitely.
|
|
117
|
+
* Use this for dev/staging environments where you want to wait indefinitely for resources.
|
|
118
|
+
*
|
|
119
|
+
* @example
|
|
120
|
+
* {
|
|
121
|
+
* locatorConfig: {
|
|
122
|
+
* queueUrl: '...',
|
|
123
|
+
* startupResourcePolling: {
|
|
124
|
+
* enabled: true,
|
|
125
|
+
* timeoutMs: NO_TIMEOUT,
|
|
126
|
+
* }
|
|
127
|
+
* }
|
|
128
|
+
* }
|
|
129
|
+
*/
|
|
130
|
+
export declare const NO_TIMEOUT: unique symbol;
|
|
131
|
+
/**
|
|
132
|
+
* Configuration for startup resource polling mode when resources may not exist at startup.
|
|
133
|
+
*
|
|
134
|
+
* This is useful in scenarios where services have cross-dependencies:
|
|
135
|
+
* - Service A needs to subscribe to Service B's topic
|
|
136
|
+
* - Service B needs to subscribe to Service A's topic
|
|
137
|
+
* - Neither can deploy first without the other's topic existing
|
|
138
|
+
*
|
|
139
|
+
* When `startupResourcePolling` is provided with `enabled: true` inside `locatorConfig`,
|
|
140
|
+
* the consumer will poll for the topic/queue to become available instead of failing immediately.
|
|
141
|
+
*
|
|
142
|
+
* @example
|
|
143
|
+
* // Enable with 5 minute timeout
|
|
144
|
+
* {
|
|
145
|
+
* locatorConfig: {
|
|
146
|
+
* queueUrl: '...',
|
|
147
|
+
* startupResourcePolling: {
|
|
148
|
+
* enabled: true,
|
|
149
|
+
* timeoutMs: 5 * 60 * 1000,
|
|
150
|
+
* }
|
|
151
|
+
* }
|
|
152
|
+
* }
|
|
153
|
+
*
|
|
154
|
+
* @example
|
|
155
|
+
* // Poll indefinitely (useful for dev/staging environments)
|
|
156
|
+
* {
|
|
157
|
+
* locatorConfig: {
|
|
158
|
+
* queueUrl: '...',
|
|
159
|
+
* startupResourcePolling: {
|
|
160
|
+
* enabled: true,
|
|
161
|
+
* timeoutMs: NO_TIMEOUT,
|
|
162
|
+
* }
|
|
163
|
+
* }
|
|
164
|
+
* }
|
|
165
|
+
*
|
|
166
|
+
* @example
|
|
167
|
+
* // Custom timeout and interval
|
|
168
|
+
* {
|
|
169
|
+
* locatorConfig: {
|
|
170
|
+
* queueUrl: '...',
|
|
171
|
+
* startupResourcePolling: {
|
|
172
|
+
* enabled: true,
|
|
173
|
+
* timeoutMs: 10 * 60 * 1000, // 10 minutes
|
|
174
|
+
* pollingIntervalMs: 10000,
|
|
175
|
+
* }
|
|
176
|
+
* }
|
|
177
|
+
* }
|
|
178
|
+
*/
|
|
179
|
+
export type StartupResourcePollingConfig = {
|
|
180
|
+
/**
|
|
181
|
+
* Controls whether polling is enabled.
|
|
182
|
+
* Must be set to true to enable polling.
|
|
183
|
+
*/
|
|
184
|
+
enabled?: boolean;
|
|
185
|
+
/**
|
|
186
|
+
* Maximum time in milliseconds to wait for the resource to become available.
|
|
187
|
+
* Use `NO_TIMEOUT` to disable timeout and poll indefinitely.
|
|
188
|
+
*/
|
|
189
|
+
timeoutMs: number | typeof NO_TIMEOUT;
|
|
190
|
+
/**
|
|
191
|
+
* Interval in milliseconds between polling attempts.
|
|
192
|
+
* Default: 5000 (5 seconds)
|
|
193
|
+
*/
|
|
194
|
+
pollingIntervalMs?: number;
|
|
195
|
+
/**
|
|
196
|
+
* Whether to throw an error when timeout is reached.
|
|
197
|
+
* - `true` (default): Throws `StartupResourcePollingTimeoutError` when timeout is reached
|
|
198
|
+
* - `false`: Reports the error via errorReporter, resets the timeout counter, and continues polling
|
|
199
|
+
*
|
|
200
|
+
* Use `false` when you want to be notified about prolonged unavailability but don't want to fail.
|
|
201
|
+
* Default: true
|
|
202
|
+
*/
|
|
203
|
+
throwOnTimeout?: boolean;
|
|
204
|
+
/**
|
|
205
|
+
* Whether to run polling in non-blocking mode.
|
|
206
|
+
* - `false` (default): init() waits for the resource to become available before resolving
|
|
207
|
+
* - `true`: If resource is not immediately available, init() resolves immediately and
|
|
208
|
+
* polling continues in the background. When the resource becomes available,
|
|
209
|
+
* the `onResourceAvailable` callback is invoked.
|
|
210
|
+
*
|
|
211
|
+
* Use `true` when you want the service to start quickly without waiting for dependencies.
|
|
212
|
+
* Default: false
|
|
213
|
+
*/
|
|
214
|
+
nonBlocking?: boolean;
|
|
215
|
+
};
|
|
216
|
+
/**
|
|
217
|
+
* Base type for queue locator configurations that includes startup resource polling.
|
|
218
|
+
* Protocol-specific locator types should extend this.
|
|
219
|
+
*/
|
|
220
|
+
export type BaseQueueLocatorType = {
|
|
221
|
+
/**
|
|
222
|
+
* Configuration for startup resource polling mode.
|
|
223
|
+
* When enabled, the consumer will poll for the resource to become available
|
|
224
|
+
* instead of failing immediately.
|
|
225
|
+
*/
|
|
226
|
+
startupResourcePolling?: StartupResourcePollingConfig;
|
|
227
|
+
};
|
|
83
228
|
type NewQueueOptions<CreationConfigType extends CommonCreationConfigType> = {
|
|
84
229
|
creationConfig?: CreationConfigType;
|
|
85
230
|
};
|
|
@@ -1,2 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Symbol to indicate no timeout - polling will continue indefinitely.
|
|
3
|
+
* Use this for dev/staging environments where you want to wait indefinitely for resources.
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* {
|
|
7
|
+
* locatorConfig: {
|
|
8
|
+
* queueUrl: '...',
|
|
9
|
+
* startupResourcePolling: {
|
|
10
|
+
* enabled: true,
|
|
11
|
+
* timeoutMs: NO_TIMEOUT,
|
|
12
|
+
* }
|
|
13
|
+
* }
|
|
14
|
+
* }
|
|
15
|
+
*/
|
|
16
|
+
export const NO_TIMEOUT = Symbol('NO_TIMEOUT');
|
|
2
17
|
//# sourceMappingURL=queueOptionsTypes.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"queueOptionsTypes.js","sourceRoot":"","sources":["../../lib/types/queueOptionsTypes.ts"],"names":[],"mappings":""}
|
|
1
|
+
{"version":3,"file":"queueOptionsTypes.js","sourceRoot":"","sources":["../../lib/types/queueOptionsTypes.ts"],"names":[],"mappings":"AAoIA;;;;;;;;;;;;;;GAcG;AACH,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC,YAAY,CAAC,CAAA"}
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import type { CommonLogger, ErrorReporter } from '@lokalise/node-core';
|
|
2
|
+
import { type StartupResourcePollingConfig } from '../types/queueOptionsTypes.ts';
|
|
3
|
+
export type StartupResourcePollingCheckResult<T> = {
|
|
4
|
+
isAvailable: true;
|
|
5
|
+
result: T;
|
|
6
|
+
} | {
|
|
7
|
+
isAvailable: false;
|
|
8
|
+
};
|
|
9
|
+
export type WaitForResourceOptions<T> = {
|
|
10
|
+
/**
|
|
11
|
+
* Startup resource polling configuration
|
|
12
|
+
*/
|
|
13
|
+
config: StartupResourcePollingConfig;
|
|
14
|
+
/**
|
|
15
|
+
* Function that checks if the resource is available.
|
|
16
|
+
* Should return { isAvailable: true, result: T } when resource exists,
|
|
17
|
+
* or { isAvailable: false } when resource doesn't exist.
|
|
18
|
+
* Should throw on unexpected errors.
|
|
19
|
+
*/
|
|
20
|
+
checkFn: () => Promise<StartupResourcePollingCheckResult<T>>;
|
|
21
|
+
/**
|
|
22
|
+
* Human-readable name of the resource for logging
|
|
23
|
+
*/
|
|
24
|
+
resourceName: string;
|
|
25
|
+
/**
|
|
26
|
+
* Logger instance for progress logging
|
|
27
|
+
*/
|
|
28
|
+
logger?: CommonLogger;
|
|
29
|
+
/**
|
|
30
|
+
* Error reporter for reporting timeout errors when throwOnTimeout is false.
|
|
31
|
+
* Required when config.throwOnTimeout is false.
|
|
32
|
+
*/
|
|
33
|
+
errorReporter?: ErrorReporter;
|
|
34
|
+
/**
|
|
35
|
+
* Callback invoked when resource becomes available in non-blocking mode.
|
|
36
|
+
* Only used when config.nonBlocking is true and the resource was not immediately available.
|
|
37
|
+
*/
|
|
38
|
+
onResourceAvailable?: (result: T) => void;
|
|
39
|
+
};
|
|
40
|
+
export declare class StartupResourcePollingTimeoutError extends Error {
|
|
41
|
+
readonly resourceName: string;
|
|
42
|
+
readonly timeoutMs: number;
|
|
43
|
+
constructor(resourceName: string, timeoutMs: number);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Waits for a resource to become available by polling.
|
|
47
|
+
* This is used for startup resource polling mode where resources may not exist at startup.
|
|
48
|
+
*
|
|
49
|
+
* @param options - Configuration and check function
|
|
50
|
+
* @returns The result from the check function when resource becomes available,
|
|
51
|
+
* or undefined if nonBlocking is true and resource was not immediately available
|
|
52
|
+
* @throws StartupResourcePollingTimeoutError if timeout is reached and throwOnTimeout is true (default)
|
|
53
|
+
*/
|
|
54
|
+
export declare function waitForResource<T>(options: WaitForResourceOptions<T>): Promise<T | undefined>;
|
|
55
|
+
/**
|
|
56
|
+
* Helper to check if startup resource polling is enabled.
|
|
57
|
+
* Returns true only when config is provided and enabled is explicitly true.
|
|
58
|
+
*/
|
|
59
|
+
export declare function isStartupResourcePollingEnabled(config?: StartupResourcePollingConfig): config is StartupResourcePollingConfig;
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { setTimeout } from 'node:timers/promises';
|
|
2
|
+
import { NO_TIMEOUT } from "../types/queueOptionsTypes.js";
|
|
3
|
+
const DEFAULT_POLLING_INTERVAL_MS = 5000;
|
|
4
|
+
export class StartupResourcePollingTimeoutError extends Error {
|
|
5
|
+
resourceName;
|
|
6
|
+
timeoutMs;
|
|
7
|
+
constructor(resourceName, timeoutMs) {
|
|
8
|
+
super(`Timeout waiting for resource "${resourceName}" to become available after ${timeoutMs}ms. ` +
|
|
9
|
+
'The resource may not exist or there may be a configuration issue.');
|
|
10
|
+
this.name = 'StartupResourcePollingTimeoutError';
|
|
11
|
+
this.resourceName = resourceName;
|
|
12
|
+
this.timeoutMs = timeoutMs;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
function checkTimeoutExceeded(hasTimeout, timeoutMs, startTime, resourceName, attemptCount, logger) {
|
|
16
|
+
if (!hasTimeout)
|
|
17
|
+
return { exceeded: false };
|
|
18
|
+
const elapsedMs = Date.now() - startTime;
|
|
19
|
+
if (elapsedMs >= timeoutMs) {
|
|
20
|
+
logger?.error({
|
|
21
|
+
message: `Timeout waiting for resource "${resourceName}" to become available`,
|
|
22
|
+
resourceName,
|
|
23
|
+
timeoutMs,
|
|
24
|
+
attemptCount,
|
|
25
|
+
elapsedMs,
|
|
26
|
+
});
|
|
27
|
+
return {
|
|
28
|
+
exceeded: true,
|
|
29
|
+
error: new StartupResourcePollingTimeoutError(resourceName, timeoutMs),
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
return { exceeded: false };
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Handles timeout condition - either throws or reports and returns new timeout count.
|
|
36
|
+
* @returns Updated timeout count after handling
|
|
37
|
+
*/
|
|
38
|
+
function handleTimeout(params) {
|
|
39
|
+
const { timeoutResult, throwOnTimeout, resourceName, timeoutMs, attemptCount, timeoutCount, logger, errorReporter, } = params;
|
|
40
|
+
if (throwOnTimeout) {
|
|
41
|
+
throw timeoutResult.error;
|
|
42
|
+
}
|
|
43
|
+
// Report error and reset timeout counter
|
|
44
|
+
const newTimeoutCount = timeoutCount + 1;
|
|
45
|
+
errorReporter?.report({
|
|
46
|
+
error: timeoutResult.error,
|
|
47
|
+
context: {
|
|
48
|
+
resourceName,
|
|
49
|
+
timeoutMs,
|
|
50
|
+
attemptCount,
|
|
51
|
+
timeoutCount: newTimeoutCount,
|
|
52
|
+
},
|
|
53
|
+
});
|
|
54
|
+
logger?.warn({
|
|
55
|
+
message: `Timeout waiting for resource "${resourceName}", resetting timeout counter and continuing`,
|
|
56
|
+
resourceName,
|
|
57
|
+
timeoutMs,
|
|
58
|
+
attemptCount,
|
|
59
|
+
timeoutCount: newTimeoutCount,
|
|
60
|
+
});
|
|
61
|
+
return newTimeoutCount;
|
|
62
|
+
}
|
|
63
|
+
function logResourceAvailable(resourceName, attemptCount, startTime, logger) {
|
|
64
|
+
const elapsedMs = Date.now() - startTime;
|
|
65
|
+
logger?.info({
|
|
66
|
+
message: `Resource "${resourceName}" is now available`,
|
|
67
|
+
resourceName,
|
|
68
|
+
attemptCount,
|
|
69
|
+
elapsedMs,
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Internal polling loop that waits for a resource to become available.
|
|
74
|
+
* Separated from main function to support non-blocking mode.
|
|
75
|
+
*/
|
|
76
|
+
async function pollForResource(options, pollingIntervalMs, hasTimeout, timeoutMs, throwOnTimeout, initialAttemptCount) {
|
|
77
|
+
const { checkFn, resourceName, logger, errorReporter } = options;
|
|
78
|
+
let startTime = Date.now();
|
|
79
|
+
let attemptCount = initialAttemptCount;
|
|
80
|
+
let timeoutCount = 0;
|
|
81
|
+
while (true) {
|
|
82
|
+
attemptCount++;
|
|
83
|
+
const timeoutResult = checkTimeoutExceeded(hasTimeout, timeoutMs, startTime, resourceName, attemptCount, logger);
|
|
84
|
+
if (timeoutResult.exceeded) {
|
|
85
|
+
timeoutCount = handleTimeout({
|
|
86
|
+
timeoutResult,
|
|
87
|
+
throwOnTimeout,
|
|
88
|
+
resourceName,
|
|
89
|
+
timeoutMs,
|
|
90
|
+
attemptCount,
|
|
91
|
+
timeoutCount,
|
|
92
|
+
logger,
|
|
93
|
+
errorReporter,
|
|
94
|
+
});
|
|
95
|
+
startTime = Date.now();
|
|
96
|
+
}
|
|
97
|
+
const result = await checkFn().catch((error) => {
|
|
98
|
+
// Unexpected error during check - log and rethrow
|
|
99
|
+
logger?.error({
|
|
100
|
+
message: `Error checking resource availability for "${resourceName}"`,
|
|
101
|
+
resourceName,
|
|
102
|
+
error,
|
|
103
|
+
attemptCount,
|
|
104
|
+
});
|
|
105
|
+
throw error;
|
|
106
|
+
});
|
|
107
|
+
if (result.isAvailable) {
|
|
108
|
+
logResourceAvailable(resourceName, attemptCount, startTime, logger);
|
|
109
|
+
return result.result;
|
|
110
|
+
}
|
|
111
|
+
// Resource not available yet, log and wait
|
|
112
|
+
if (attemptCount === 1 || attemptCount % 12 === 0) {
|
|
113
|
+
// Log on first attempt and then every minute (assuming 5s interval)
|
|
114
|
+
const elapsedMs = Date.now() - startTime;
|
|
115
|
+
logger?.debug({
|
|
116
|
+
message: `Resource "${resourceName}" not available yet, will retry`,
|
|
117
|
+
resourceName,
|
|
118
|
+
attemptCount,
|
|
119
|
+
elapsedMs,
|
|
120
|
+
nextRetryInMs: pollingIntervalMs,
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
// Wait before next attempt
|
|
124
|
+
await setTimeout(pollingIntervalMs);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Waits for a resource to become available by polling.
|
|
129
|
+
* This is used for startup resource polling mode where resources may not exist at startup.
|
|
130
|
+
*
|
|
131
|
+
* @param options - Configuration and check function
|
|
132
|
+
* @returns The result from the check function when resource becomes available,
|
|
133
|
+
* or undefined if nonBlocking is true and resource was not immediately available
|
|
134
|
+
* @throws StartupResourcePollingTimeoutError if timeout is reached and throwOnTimeout is true (default)
|
|
135
|
+
*/
|
|
136
|
+
export async function waitForResource(options) {
|
|
137
|
+
const { config, checkFn, resourceName, logger, onResourceAvailable } = options;
|
|
138
|
+
const pollingIntervalMs = config.pollingIntervalMs ?? DEFAULT_POLLING_INTERVAL_MS;
|
|
139
|
+
const hasTimeout = config.timeoutMs !== NO_TIMEOUT;
|
|
140
|
+
const timeoutMs = hasTimeout ? config.timeoutMs : 0;
|
|
141
|
+
const throwOnTimeout = config.throwOnTimeout !== false;
|
|
142
|
+
const nonBlocking = config.nonBlocking === true;
|
|
143
|
+
logger?.info({
|
|
144
|
+
message: `Waiting for resource "${resourceName}" to become available`,
|
|
145
|
+
resourceName,
|
|
146
|
+
pollingIntervalMs,
|
|
147
|
+
timeoutMs: hasTimeout ? timeoutMs : 'NO_TIMEOUT',
|
|
148
|
+
throwOnTimeout,
|
|
149
|
+
nonBlocking,
|
|
150
|
+
});
|
|
151
|
+
// First check - always done synchronously
|
|
152
|
+
const initialResult = await checkFn().catch((error) => {
|
|
153
|
+
logger?.error({
|
|
154
|
+
message: `Error checking resource availability for "${resourceName}"`,
|
|
155
|
+
resourceName,
|
|
156
|
+
error,
|
|
157
|
+
attemptCount: 1,
|
|
158
|
+
});
|
|
159
|
+
throw error;
|
|
160
|
+
});
|
|
161
|
+
if (initialResult.isAvailable) {
|
|
162
|
+
logResourceAvailable(resourceName, 1, Date.now(), logger);
|
|
163
|
+
return initialResult.result;
|
|
164
|
+
}
|
|
165
|
+
// Resource not available on first check
|
|
166
|
+
if (nonBlocking) {
|
|
167
|
+
// Start background polling and return immediately
|
|
168
|
+
logger?.info({
|
|
169
|
+
message: `Resource "${resourceName}" not immediately available, starting background polling`,
|
|
170
|
+
resourceName,
|
|
171
|
+
pollingIntervalMs,
|
|
172
|
+
});
|
|
173
|
+
// Fire and forget - start polling in background
|
|
174
|
+
setTimeout(pollingIntervalMs).then(() => {
|
|
175
|
+
pollForResource(options, pollingIntervalMs, hasTimeout, timeoutMs, throwOnTimeout, 1)
|
|
176
|
+
.then((result) => {
|
|
177
|
+
onResourceAvailable?.(result);
|
|
178
|
+
})
|
|
179
|
+
.catch((error) => {
|
|
180
|
+
logger?.error({
|
|
181
|
+
message: `Background polling for resource "${resourceName}" failed`,
|
|
182
|
+
resourceName,
|
|
183
|
+
error,
|
|
184
|
+
});
|
|
185
|
+
});
|
|
186
|
+
});
|
|
187
|
+
return undefined;
|
|
188
|
+
}
|
|
189
|
+
// Blocking mode - continue polling and wait for result
|
|
190
|
+
return pollForResource(options, pollingIntervalMs, hasTimeout, timeoutMs, throwOnTimeout, 1);
|
|
191
|
+
}
|
|
192
|
+
/**
|
|
193
|
+
* Helper to check if startup resource polling is enabled.
|
|
194
|
+
* Returns true only when config is provided and enabled is explicitly true.
|
|
195
|
+
*/
|
|
196
|
+
export function isStartupResourcePollingEnabled(config) {
|
|
197
|
+
return config?.enabled === true;
|
|
198
|
+
}
|
|
199
|
+
//# sourceMappingURL=startupResourcePollingUtils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"startupResourcePollingUtils.js","sourceRoot":"","sources":["../../lib/utils/startupResourcePollingUtils.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@message-queue-toolkit/core",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "25.1.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "Useful utilities, interfaces and base classes for message queue handling. Supports AMQP and SQS with a common abstraction on top currently",
|
|
6
6
|
"maintainers": [
|
|
@@ -28,7 +28,8 @@
|
|
|
28
28
|
"@lokalise/node-core": "^14.2.0",
|
|
29
29
|
"@lokalise/universal-ts-utils": "^4.5.1",
|
|
30
30
|
"@message-queue-toolkit/schemas": "^7.0.0",
|
|
31
|
-
"
|
|
31
|
+
"dot-prop": "^10.1.0",
|
|
32
|
+
"fast-equals": "^6.0.0",
|
|
32
33
|
"json-stream-stringify": "^3.1.6",
|
|
33
34
|
"tmp": "^0.2.3",
|
|
34
35
|
"toad-cache": "^3.7.0"
|
|
@@ -40,7 +41,7 @@
|
|
|
40
41
|
"@biomejs/biome": "^2.3.8",
|
|
41
42
|
"@lokalise/biome-config": "^3.1.0",
|
|
42
43
|
"@lokalise/tsconfig": "^3.0.0",
|
|
43
|
-
"@types/node": "^
|
|
44
|
+
"@types/node": "^25.0.2",
|
|
44
45
|
"@types/tmp": "^0.2.6",
|
|
45
46
|
"@vitest/coverage-v8": "^3.2.4",
|
|
46
47
|
"awilix": "^12.0.5",
|
|
@@ -48,7 +49,7 @@
|
|
|
48
49
|
"rimraf": "^6.0.1",
|
|
49
50
|
"typescript": "^5.9.2",
|
|
50
51
|
"vitest": "^3.2.4",
|
|
51
|
-
"zod": "^4.
|
|
52
|
+
"zod": "^4.1.13"
|
|
52
53
|
},
|
|
53
54
|
"homepage": "https://github.com/kibertoad/message-queue-toolkit",
|
|
54
55
|
"repository": {
|