Skip to content
This repository was archived by the owner on Mar 17, 2026. It is now read-only.

Commit 46b83ba

Browse files
authored
fix: deprecate maxExtension in favour of maxExtensionMinutes (#1402)
* fix: deprecate maxExtension in favour of maxExtensionMinutes Background: maxExtension was incorrectly interpreted as seconds in the LeaseManager. This means that if users were relying on client side lease extension in subscribers, they would not actually extend leases for 60 minutes, but only 60 seconds. Also if the user passed in values, they'd be interpreted incorrectly. This PR deprecates the old field in favour of a new one that's explicitly named like the defaults, but also converts the old value if needed. * fix: only allow one of maxExtension or maxExtensionMinutes
1 parent c96881d commit 46b83ba

2 files changed

Lines changed: 53 additions & 8 deletions

File tree

src/lease-manager.ts

Lines changed: 30 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,11 @@ import {defaultOptions} from './default-options';
2121
export interface FlowControlOptions {
2222
allowExcessMessages?: boolean;
2323
maxBytes?: number;
24-
maxExtension?: number;
2524
maxMessages?: number;
25+
maxExtensionMinutes?: number;
26+
27+
/** @deprecated Use maxExtensionMinutes. */
28+
maxExtension?: number;
2629
}
2730

2831
/**
@@ -36,7 +39,7 @@ export interface FlowControlOptions {
3639
* @property {number} [maxBytes=104857600] The desired amount of memory to
3740
* allow message data to consume. (Default: 100MB) It's possible that this
3841
* value will be exceeded, since messages are received in batches.
39-
* @property {number} [maxExtension=60] The maximum duration (in seconds)
42+
* @property {number} [maxExtensionMinutes=60] The maximum duration (in minutes)
4043
* to extend the message deadline before redelivering.
4144
* @property {number} [maxMessages=1000] The desired number of messages to allow
4245
* in memory before pausing the message stream. Unless allowExcessMessages
@@ -179,13 +182,34 @@ export class LeaseManager extends EventEmitter {
179182
* Sets options for the LeaseManager.
180183
*
181184
* @param {FlowControlOptions} [options] The options.
185+
*
186+
* @throws {RangeError} If both maxExtension and maxExtensionMinutes are set.
187+
*
182188
* @private
183189
*/
184190
setOptions(options: FlowControlOptions): void {
191+
// Convert the old deprecated maxExtension to avoid breaking clients,
192+
// but allow only one.
193+
if (
194+
options.maxExtension !== undefined &&
195+
options.maxExtensionMinutes !== undefined
196+
) {
197+
throw new RangeError(
198+
'Only one of "maxExtension" or "maxExtensionMinutes" may be set for subscriber lease management options'
199+
);
200+
}
201+
if (
202+
options.maxExtension !== undefined &&
203+
options.maxExtensionMinutes === undefined
204+
) {
205+
options.maxExtensionMinutes = options.maxExtension / 60;
206+
delete options.maxExtension;
207+
}
208+
185209
const defaults: FlowControlOptions = {
186210
allowExcessMessages: true,
187211
maxBytes: defaultOptions.subscription.maxOutstandingBytes,
188-
maxExtension: defaultOptions.subscription.maxExtensionMinutes,
212+
maxExtensionMinutes: defaultOptions.subscription.maxExtensionMinutes,
189213
maxMessages: defaultOptions.subscription.maxOutstandingMessages,
190214
};
191215

@@ -229,9 +253,10 @@ export class LeaseManager extends EventEmitter {
229253
const deadline = this._subscriber.ackDeadline;
230254

231255
for (const message of this._messages) {
232-
const lifespan = (Date.now() - message.received) / 1000;
256+
// Lifespan here is in minutes.
257+
const lifespan = (Date.now() - message.received) / (60 * 1000);
233258

234-
if (lifespan < this._options.maxExtension!) {
259+
if (lifespan < this._options.maxExtensionMinutes!) {
235260
message.modAck(deadline);
236261
} else {
237262
this.remove(message);

test/lease-manager.ts

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -224,11 +224,31 @@ describe('LeaseManager', () => {
224224
});
225225
});
226226

227-
it('should remove any messages that pass the maxExtension value', () => {
228-
const maxExtension = (expectedTimeout - 100) / 1000;
227+
it('should properly convert any legacy maxExtension values', () => {
228+
const maxExtension = 60 * 1000;
229+
leaseManager.setOptions({maxExtension});
230+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
231+
const options = (leaseManager as any)._options;
232+
assert.strictEqual(options.maxExtensionMinutes, maxExtension / 60);
233+
assert.strictEqual(options.maxExtension, undefined);
234+
});
235+
236+
it('should not allow both maxExtension and maxExtensionMinutes', () => {
237+
assert.throws(() => {
238+
leaseManager.setOptions({
239+
maxExtension: 10,
240+
maxExtensionMinutes: 10,
241+
});
242+
});
243+
});
244+
245+
it('should remove any messages that pass the maxExtensionMinutes value', () => {
246+
const maxExtensionSeconds = (expectedTimeout - 100) / 1000;
229247
const badMessages = [new FakeMessage(), new FakeMessage()];
230248

231-
leaseManager.setOptions({maxExtension});
249+
leaseManager.setOptions({
250+
maxExtensionMinutes: maxExtensionSeconds / 60,
251+
});
232252
badMessages.forEach(message =>
233253
leaseManager.add(message as {} as Message)
234254
);

0 commit comments

Comments
 (0)