@message-queue-toolkit/core 25.0.0 → 25.2.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 CHANGED
@@ -1,5 +1,5 @@
1
1
  # @message-queue-toolkit/core
2
-
2
+
3
3
  Core library for message-queue-toolkit. Provides foundational abstractions, utilities, and base classes for building message queue publishers and consumers.
4
4
 
5
5
  ## Table of Contents
package/dist/index.d.ts CHANGED
@@ -29,5 +29,6 @@ export { isProduction, reloadConfig } from './utils/envUtils.ts';
29
29
  export { isShallowSubset, objectMatches } from './utils/matchUtils.ts';
30
30
  export { type ParseMessageResult, parseMessage } from './utils/parseUtils.ts';
31
31
  export { objectToBuffer } from './utils/queueUtils.ts';
32
+ export { isStartupResourcePollingEnabled, type PollingErrorCallback, type PollingErrorContext, type StartupResourcePollingCheckResult, StartupResourcePollingTimeoutError, type WaitForResourceOptions, waitForResource, } from './utils/startupResourcePollingUtils.ts';
32
33
  export { toDatePreprocessor } from './utils/toDateProcessor.ts';
33
34
  export { waitAndRetry } from './utils/waitUtils.ts';
package/dist/index.js CHANGED
@@ -24,6 +24,7 @@ export { isProduction, reloadConfig } from "./utils/envUtils.js";
24
24
  export { isShallowSubset, objectMatches } from "./utils/matchUtils.js";
25
25
  export { parseMessage } from "./utils/parseUtils.js";
26
26
  export { objectToBuffer } from "./utils/queueUtils.js";
27
+ export { isStartupResourcePollingEnabled, StartupResourcePollingTimeoutError, waitForResource, } from "./utils/startupResourcePollingUtils.js";
27
28
  export { toDatePreprocessor } from "./utils/toDateProcessor.js";
28
29
  export { waitAndRetry } from "./utils/waitUtils.js";
29
30
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAA;AACxE,OAAO,EACL,cAAc,EACd,yBAAyB,EACzB,sBAAsB,GACvB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAA;AAC3E,cAAc,8BAA8B,CAAA;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AACzD,cAAc,wBAAwB,CAAA;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAA;AAC7D,cAAc,oDAAoD,CAAA;AAClE,OAAO,EAGL,0BAA0B,EAG1B,kBAAkB,GAEnB,MAAM,sDAAsD,CAAA;AAC7D,cAAc,kCAAkC,CAAA;AAChD,cAAc,8BAA8B,CAAA;AAC5C,OAAO,EACL,gCAAgC,EAChC,wCAAwC,EAExC,kBAAkB,GAEnB,MAAM,mDAAmD,CAAA;AAS1D,OAAO,EACL,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,sCAAsC,CAAA;AAC7C,cAAc,sCAAsC,CAAA;AACpD,OAAO,EACL,oBAAoB,GAGrB,MAAM,kCAAkC,CAAA;AAWzC,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,2BAA2B,GAE5B,MAAM,8BAA8B,CAAA;AACrC,OAAO,EACL,gBAAgB,EAChB,UAAU,EAGV,iBAAiB,EAEjB,iBAAiB,GAClB,MAAM,wBAAwB,CAAA;AAM/B,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAA;AAM3E,OAAO,EACL,4BAA4B,EAC5B,0BAA0B,EAC1B,uBAAuB,EACvB,6BAA6B,EAC7B,kBAAkB,GACnB,MAAM,iCAAiC,CAAA;AAUxC,cAAc,8BAA8B,CAAA;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAC1D,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAChE,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACtE,OAAO,EAA2B,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAA;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../lib/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,wBAAwB,EAAE,MAAM,+BAA+B,CAAA;AACxE,OAAO,EACL,cAAc,EACd,yBAAyB,EACzB,sBAAsB,GACvB,MAAM,oBAAoB,CAAA;AAC3B,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAA;AAC3E,cAAc,8BAA8B,CAAA;AAC5C,OAAO,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAA;AACnE,OAAO,EAAE,aAAa,EAAE,MAAM,2BAA2B,CAAA;AACzD,cAAc,wBAAwB,CAAA;AACtC,OAAO,EAAE,YAAY,EAAE,MAAM,gCAAgC,CAAA;AAC7D,cAAc,oDAAoD,CAAA;AAClE,OAAO,EAGL,0BAA0B,EAG1B,kBAAkB,GAEnB,MAAM,sDAAsD,CAAA;AAC7D,cAAc,kCAAkC,CAAA;AAChD,cAAc,8BAA8B,CAAA;AAC5C,OAAO,EACL,gCAAgC,EAChC,wCAAwC,EAExC,kBAAkB,GAEnB,MAAM,mDAAmD,CAAA;AAS1D,OAAO,EACL,sBAAsB,EACtB,yBAAyB,GAC1B,MAAM,sCAAsC,CAAA;AAC7C,cAAc,sCAAsC,CAAA;AACpD,OAAO,EACL,oBAAoB,GAGrB,MAAM,kCAAkC,CAAA;AAWzC,OAAO,EACL,gBAAgB,EAChB,oBAAoB,EACpB,2BAA2B,GAE5B,MAAM,8BAA8B,CAAA;AACrC,OAAO,EACL,gBAAgB,EAChB,UAAU,EAGV,iBAAiB,EAEjB,iBAAiB,GAClB,MAAM,wBAAwB,CAAA;AAM/B,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAA;AAM3E,OAAO,EACL,4BAA4B,EAC5B,0BAA0B,EAC1B,uBAAuB,EACvB,6BAA6B,EAC7B,kBAAkB,GACnB,MAAM,iCAAiC,CAAA;AAUxC,cAAc,8BAA8B,CAAA;AAC5C,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAA;AAC1D,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAA;AAChE,OAAO,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAA;AACtE,OAAO,EAA2B,YAAY,EAAE,MAAM,uBAAuB,CAAA;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAA;AACtD,OAAO,EACL,+BAA+B,EAI/B,kCAAkC,EAElC,eAAe,GAChB,MAAM,wCAAwC,CAAA;AAC/C,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAA;AAC/D,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA"}
@@ -5,7 +5,7 @@ export declare class JsonStreamStringifySerializer implements PayloadSerializer
5
5
  private readonly temporaryFilePathResolver;
6
6
  constructor(temporaryFilePathResolver?: TemporaryFilePathResolver);
7
7
  serialize(payload: unknown): Promise<{
8
- value: import("stream").Readable;
8
+ value: import("node:stream").Readable;
9
9
  size: number;
10
10
  destroy: () => Promise<void>;
11
11
  }>;
@@ -1,4 +1,4 @@
1
- import type { CommonLogger, TransactionObservabilityManager } from '@lokalise/node-core';
1
+ import type { CommonLogger, ErrorReporter, TransactionObservabilityManager } from '@lokalise/node-core';
2
2
  import type { ZodSchema } from 'zod/v4';
3
3
  import type { PublicHandlerSpy } from '../queues/HandlerSpy.ts';
4
4
  export interface QueueConsumer {
@@ -28,5 +28,6 @@ export interface AsyncPublisher<MessagePayloadType extends object, MessageOption
28
28
  export type { TransactionObservabilityManager };
29
29
  export type ExtraParams = {
30
30
  logger?: CommonLogger;
31
+ errorReporter?: ErrorReporter;
31
32
  };
32
33
  export type SchemaMap<SupportedMessageTypes extends string> = Record<SupportedMessageTypes, ZodSchema<any>>;
@@ -112,6 +112,119 @@ export type DeletionConfig = {
112
112
  waitForConfirmation?: boolean;
113
113
  forceDeleteInProduction?: boolean;
114
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
+ };
115
228
  type NewQueueOptions<CreationConfigType extends CommonCreationConfigType> = {
116
229
  creationConfig?: CreationConfigType;
117
230
  };
@@ -1,2 +1,17 @@
1
- export {};
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,79 @@
1
+ import { type CommonLogger, type ErrorReporter } from '@lokalise/node-core';
2
+ import { type StartupResourcePollingConfig } from '../types/queueOptionsTypes.ts';
3
+ /**
4
+ * Context passed to error callbacks indicating whether the error is final.
5
+ */
6
+ export type PollingErrorContext = {
7
+ /**
8
+ * If true, the operation has stopped and will not retry.
9
+ * If false, this is a transient error and the operation will continue.
10
+ */
11
+ isFinal: boolean;
12
+ };
13
+ /**
14
+ * Callback invoked when a polling operation fails.
15
+ */
16
+ export type PollingErrorCallback = (error: Error, context: PollingErrorContext) => void;
17
+ export type StartupResourcePollingCheckResult<T> = {
18
+ isAvailable: true;
19
+ result: T;
20
+ } | {
21
+ isAvailable: false;
22
+ };
23
+ export type WaitForResourceOptions<T> = {
24
+ /**
25
+ * Startup resource polling configuration
26
+ */
27
+ config: StartupResourcePollingConfig;
28
+ /**
29
+ * Function that checks if the resource is available.
30
+ * Should return { isAvailable: true, result: T } when resource exists,
31
+ * or { isAvailable: false } when resource doesn't exist.
32
+ * Should throw on unexpected errors.
33
+ */
34
+ checkFn: () => Promise<StartupResourcePollingCheckResult<T>>;
35
+ /**
36
+ * Human-readable name of the resource for logging
37
+ */
38
+ resourceName: string;
39
+ /**
40
+ * Logger instance for progress logging
41
+ */
42
+ logger?: CommonLogger;
43
+ /**
44
+ * Error reporter for reporting timeout errors when throwOnTimeout is false.
45
+ * Required when config.throwOnTimeout is false.
46
+ */
47
+ errorReporter?: ErrorReporter;
48
+ /**
49
+ * Callback invoked when resource becomes available in non-blocking mode.
50
+ * Only used when config.nonBlocking is true and the resource was not immediately available.
51
+ */
52
+ onResourceAvailable?: (result: T) => void;
53
+ /**
54
+ * Callback invoked when background polling fails in non-blocking mode.
55
+ * This can happen due to polling timeout or unexpected errors during polling.
56
+ * Only used when config.nonBlocking is true.
57
+ */
58
+ onError?: PollingErrorCallback;
59
+ };
60
+ export declare class StartupResourcePollingTimeoutError extends Error {
61
+ readonly resourceName: string;
62
+ readonly timeoutMs: number;
63
+ constructor(resourceName: string, timeoutMs: number);
64
+ }
65
+ /**
66
+ * Waits for a resource to become available by polling.
67
+ * This is used for startup resource polling mode where resources may not exist at startup.
68
+ *
69
+ * @param options - Configuration and check function
70
+ * @returns The result from the check function when resource becomes available,
71
+ * or undefined if nonBlocking is true and resource was not immediately available
72
+ * @throws StartupResourcePollingTimeoutError if timeout is reached and throwOnTimeout is true (default)
73
+ */
74
+ export declare function waitForResource<T>(options: WaitForResourceOptions<T>): Promise<T | undefined>;
75
+ /**
76
+ * Helper to check if startup resource polling is enabled.
77
+ * Returns true only when config is provided and enabled is explicitly true.
78
+ */
79
+ export declare function isStartupResourcePollingEnabled(config?: StartupResourcePollingConfig): config is StartupResourcePollingConfig;
@@ -0,0 +1,205 @@
1
+ import { setTimeout } from 'node:timers/promises';
2
+ import { isError } from '@lokalise/node-core';
3
+ import { NO_TIMEOUT } from "../types/queueOptionsTypes.js";
4
+ const DEFAULT_POLLING_INTERVAL_MS = 5000;
5
+ export class StartupResourcePollingTimeoutError extends Error {
6
+ resourceName;
7
+ timeoutMs;
8
+ constructor(resourceName, timeoutMs) {
9
+ super(`Timeout waiting for resource "${resourceName}" to become available after ${timeoutMs}ms. ` +
10
+ 'The resource may not exist or there may be a configuration issue.');
11
+ this.name = 'StartupResourcePollingTimeoutError';
12
+ this.resourceName = resourceName;
13
+ this.timeoutMs = timeoutMs;
14
+ }
15
+ }
16
+ function checkTimeoutExceeded(hasTimeout, timeoutMs, startTime, resourceName, attemptCount, logger) {
17
+ if (!hasTimeout)
18
+ return { exceeded: false };
19
+ const elapsedMs = Date.now() - startTime;
20
+ if (elapsedMs >= timeoutMs) {
21
+ logger?.error({
22
+ message: `Timeout waiting for resource "${resourceName}" to become available`,
23
+ resourceName,
24
+ timeoutMs,
25
+ attemptCount,
26
+ elapsedMs,
27
+ });
28
+ return {
29
+ exceeded: true,
30
+ error: new StartupResourcePollingTimeoutError(resourceName, timeoutMs),
31
+ };
32
+ }
33
+ return { exceeded: false };
34
+ }
35
+ /**
36
+ * Handles timeout condition - either throws or reports and returns new timeout count.
37
+ * @returns Updated timeout count after handling
38
+ */
39
+ function handleTimeout(params) {
40
+ const { timeoutResult, throwOnTimeout, resourceName, timeoutMs, attemptCount, timeoutCount, logger, errorReporter, } = params;
41
+ if (throwOnTimeout) {
42
+ throw timeoutResult.error;
43
+ }
44
+ // Report error and reset timeout counter
45
+ const newTimeoutCount = timeoutCount + 1;
46
+ errorReporter?.report({
47
+ error: timeoutResult.error,
48
+ context: {
49
+ resourceName,
50
+ timeoutMs,
51
+ attemptCount,
52
+ timeoutCount: newTimeoutCount,
53
+ },
54
+ });
55
+ logger?.warn({
56
+ message: `Timeout waiting for resource "${resourceName}", resetting timeout counter and continuing`,
57
+ resourceName,
58
+ timeoutMs,
59
+ attemptCount,
60
+ timeoutCount: newTimeoutCount,
61
+ });
62
+ return newTimeoutCount;
63
+ }
64
+ function logResourceAvailable(resourceName, attemptCount, startTime, logger) {
65
+ const elapsedMs = Date.now() - startTime;
66
+ logger?.info({
67
+ message: `Resource "${resourceName}" is now available`,
68
+ resourceName,
69
+ attemptCount,
70
+ elapsedMs,
71
+ });
72
+ }
73
+ /**
74
+ * Internal polling loop that waits for a resource to become available.
75
+ * Separated from main function to support non-blocking mode.
76
+ */
77
+ async function pollForResource(options, pollingIntervalMs, hasTimeout, timeoutMs, throwOnTimeout, initialAttemptCount) {
78
+ const { checkFn, resourceName, logger, errorReporter } = options;
79
+ let startTime = Date.now();
80
+ let attemptCount = initialAttemptCount;
81
+ let timeoutCount = 0;
82
+ while (true) {
83
+ attemptCount++;
84
+ const timeoutResult = checkTimeoutExceeded(hasTimeout, timeoutMs, startTime, resourceName, attemptCount, logger);
85
+ if (timeoutResult.exceeded) {
86
+ timeoutCount = handleTimeout({
87
+ timeoutResult,
88
+ throwOnTimeout,
89
+ resourceName,
90
+ timeoutMs,
91
+ attemptCount,
92
+ timeoutCount,
93
+ logger,
94
+ errorReporter,
95
+ });
96
+ startTime = Date.now();
97
+ }
98
+ const result = await checkFn().catch((error) => {
99
+ // Unexpected error during check - log and rethrow
100
+ logger?.error({
101
+ message: `Error checking resource availability for "${resourceName}"`,
102
+ resourceName,
103
+ error,
104
+ attemptCount,
105
+ });
106
+ throw error;
107
+ });
108
+ if (result.isAvailable) {
109
+ logResourceAvailable(resourceName, attemptCount, startTime, logger);
110
+ return result.result;
111
+ }
112
+ // Resource not available yet, log and wait
113
+ if (attemptCount === 1 || attemptCount % 12 === 0) {
114
+ // Log on first attempt and then every minute (assuming 5s interval)
115
+ const elapsedMs = Date.now() - startTime;
116
+ logger?.debug({
117
+ message: `Resource "${resourceName}" not available yet, will retry`,
118
+ resourceName,
119
+ attemptCount,
120
+ elapsedMs,
121
+ nextRetryInMs: pollingIntervalMs,
122
+ });
123
+ }
124
+ // Wait before next attempt
125
+ await setTimeout(pollingIntervalMs);
126
+ }
127
+ }
128
+ /**
129
+ * Waits for a resource to become available by polling.
130
+ * This is used for startup resource polling mode where resources may not exist at startup.
131
+ *
132
+ * @param options - Configuration and check function
133
+ * @returns The result from the check function when resource becomes available,
134
+ * or undefined if nonBlocking is true and resource was not immediately available
135
+ * @throws StartupResourcePollingTimeoutError if timeout is reached and throwOnTimeout is true (default)
136
+ */
137
+ export async function waitForResource(options) {
138
+ const { config, checkFn, resourceName, logger, onResourceAvailable } = options;
139
+ const pollingIntervalMs = config.pollingIntervalMs ?? DEFAULT_POLLING_INTERVAL_MS;
140
+ const hasTimeout = config.timeoutMs !== NO_TIMEOUT;
141
+ const timeoutMs = hasTimeout ? config.timeoutMs : 0;
142
+ const throwOnTimeout = config.throwOnTimeout !== false;
143
+ const nonBlocking = config.nonBlocking === true;
144
+ logger?.info({
145
+ message: `Waiting for resource "${resourceName}" to become available`,
146
+ resourceName,
147
+ pollingIntervalMs,
148
+ timeoutMs: hasTimeout ? timeoutMs : 'NO_TIMEOUT',
149
+ throwOnTimeout,
150
+ nonBlocking,
151
+ });
152
+ // First check - always done synchronously
153
+ const initialResult = await checkFn().catch((error) => {
154
+ logger?.error({
155
+ message: `Error checking resource availability for "${resourceName}"`,
156
+ resourceName,
157
+ error,
158
+ attemptCount: 1,
159
+ });
160
+ throw error;
161
+ });
162
+ if (initialResult.isAvailable) {
163
+ logResourceAvailable(resourceName, 1, Date.now(), logger);
164
+ return initialResult.result;
165
+ }
166
+ // Resource not available on first check
167
+ if (nonBlocking) {
168
+ // Start background polling and return immediately
169
+ logger?.info({
170
+ message: `Resource "${resourceName}" not immediately available, starting background polling`,
171
+ resourceName,
172
+ pollingIntervalMs,
173
+ });
174
+ // Fire and forget - start polling in background
175
+ const { onError } = options;
176
+ setTimeout(pollingIntervalMs).then(() => {
177
+ pollForResource(options, pollingIntervalMs, hasTimeout, timeoutMs, throwOnTimeout, 1)
178
+ .then((result) => {
179
+ onResourceAvailable?.(result);
180
+ })
181
+ .catch((err) => {
182
+ const error = isError(err) ? err : new Error(String(err));
183
+ logger?.error({
184
+ message: `Background polling for resource "${resourceName}" failed`,
185
+ resourceName,
186
+ error,
187
+ });
188
+ // isFinal: true because pollForResource only throws when it gives up
189
+ // (timeout with throwOnTimeout: true, or unexpected error)
190
+ onError?.(error, { isFinal: true });
191
+ });
192
+ });
193
+ return undefined;
194
+ }
195
+ // Blocking mode - continue polling and wait for result
196
+ return pollForResource(options, pollingIntervalMs, hasTimeout, timeoutMs, throwOnTimeout, 1);
197
+ }
198
+ /**
199
+ * Helper to check if startup resource polling is enabled.
200
+ * Returns true only when config is provided and enabled is explicitly true.
201
+ */
202
+ export function isStartupResourcePollingEnabled(config) {
203
+ return config?.enabled === true;
204
+ }
205
+ //# 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": "25.0.0",
3
+ "version": "25.2.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": [
@@ -29,7 +29,7 @@
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": "^5.2.2",
32
+ "fast-equals": "^6.0.0",
33
33
  "json-stream-stringify": "^3.1.6",
34
34
  "tmp": "^0.2.3",
35
35
  "toad-cache": "^3.7.0"
@@ -41,7 +41,7 @@
41
41
  "@biomejs/biome": "^2.3.8",
42
42
  "@lokalise/biome-config": "^3.1.0",
43
43
  "@lokalise/tsconfig": "^3.0.0",
44
- "@types/node": "^24.10.1",
44
+ "@types/node": "^25.0.2",
45
45
  "@types/tmp": "^0.2.6",
46
46
  "@vitest/coverage-v8": "^3.2.4",
47
47
  "awilix": "^12.0.5",