Skip to content

Commit a6892be

Browse files
committed
fix(queue-manager): reset fake state on reinit
1 parent 11712b3 commit a6892be

File tree

2 files changed

+107
-6
lines changed

2 files changed

+107
-6
lines changed

src/queue_manager.ts

Lines changed: 42 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,7 @@ class QueueManagerSingleton {
8787

8888
this.#validateConfig(config)
8989

90-
for (const [name, adapter] of this.#adapterInstances) {
91-
debug('destroying adapter "%s" before reinitialization', name)
92-
await adapter.destroy()
93-
}
94-
95-
this.#adapterInstances.clear()
90+
await this.#cleanupBeforeReinitialization()
9691

9792
this.#defaultAdapter = config.default
9893
this.#adapters = config.adapters
@@ -116,6 +111,47 @@ class QueueManagerSingleton {
116111
return this
117112
}
118113

114+
/**
115+
* Destroy any materialized adapters from the current configuration before
116+
* replacing it with a new one.
117+
*/
118+
async #cleanupBeforeReinitialization() {
119+
const destroyedAdapters = new Set<Adapter>()
120+
121+
await this.#destroyAdapters(this.#adapterInstances, destroyedAdapters)
122+
123+
if (this.#fakeState) {
124+
await this.#destroyAdapter('fake', this.#fakeState.fakeAdapter, destroyedAdapters)
125+
await this.#destroyAdapters(this.#fakeState.adapterInstances, destroyedAdapters)
126+
this.#fakeState = undefined
127+
}
128+
129+
this.#adapterInstances.clear()
130+
}
131+
132+
/**
133+
* Destroy a collection of adapters while avoiding double-destroying the same
134+
* instance through multiple references.
135+
*/
136+
async #destroyAdapters(adapters: Iterable<[string, Adapter]>, destroyedAdapters: Set<Adapter>) {
137+
for (const [name, adapter] of adapters) {
138+
await this.#destroyAdapter(name, adapter, destroyedAdapters)
139+
}
140+
}
141+
142+
/**
143+
* Destroy a single adapter once for the current cleanup pass.
144+
*/
145+
async #destroyAdapter(name: string, adapter: Adapter, destroyedAdapters: Set<Adapter>) {
146+
if (destroyedAdapters.has(adapter)) {
147+
return
148+
}
149+
150+
destroyedAdapters.add(adapter)
151+
debug('destroying adapter "%s" before reinitialization', name)
152+
await adapter.destroy()
153+
}
154+
119155
/**
120156
* Get an adapter instance by name.
121157
*

tests/queue_manager.spec.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,4 +238,69 @@ test.group('QueueManager', () => {
238238
assert.strictEqual(secondAdapter, adapters[1])
239239
assert.equal(destroyedCount, 1)
240240
})
241+
242+
test('should reset fake state when reinitializing', async ({ assert, cleanup }) => {
243+
type LabeledAdapter = Adapter & { label: string }
244+
245+
const createAdapter = (label: string): LabeledAdapter => ({
246+
label,
247+
setWorkerId() {},
248+
pop: async () => null,
249+
popFrom: async () => null,
250+
recoverStalledJobs: async () => 0,
251+
completeJob: async () => {},
252+
failJob: async () => {},
253+
retryJob: async () => {},
254+
getJob: async () => null,
255+
push: async () => {},
256+
pushOn: async () => {},
257+
pushLater: async () => {},
258+
pushLaterOn: async () => {},
259+
pushMany: async () => {},
260+
pushManyOn: async () => {},
261+
size: async () => 0,
262+
sizeOf: async () => 0,
263+
destroy: async () => {},
264+
upsertSchedule: async () => 'schedule-id',
265+
createSchedule: async () => 'schedule-id',
266+
getSchedule: async () => null,
267+
listSchedules: async () => [],
268+
updateSchedule: async () => {},
269+
deleteSchedule: async () => {},
270+
claimDueSchedule: async () => null,
271+
})
272+
273+
cleanup(async () => {
274+
await QueueManager.destroy()
275+
})
276+
277+
await QueueManager.init({
278+
default: 'custom',
279+
adapters: {
280+
custom: () => createAdapter('first'),
281+
},
282+
})
283+
284+
const firstAdapter = QueueManager.use() as LabeledAdapter
285+
const firstFakeAdapter = QueueManager.fake()
286+
287+
await QueueManager.init({
288+
default: 'custom',
289+
adapters: {
290+
custom: () => createAdapter('second'),
291+
},
292+
})
293+
294+
const secondFakeAdapter = QueueManager.fake()
295+
296+
assert.notStrictEqual(secondFakeAdapter, firstFakeAdapter)
297+
assert.strictEqual(QueueManager.use(), secondFakeAdapter)
298+
299+
QueueManager.restore()
300+
301+
const restoredAdapter = QueueManager.use() as LabeledAdapter
302+
303+
assert.notStrictEqual(restoredAdapter, firstAdapter)
304+
assert.equal(restoredAdapter.label, 'second')
305+
})
241306
})

0 commit comments

Comments
 (0)