Skip to content

Commit 493fb2d

Browse files
committed
test(idempotency): match split claim markers, gate the live-holder test, clean up keys
1 parent 8432e19 commit 493fb2d

1 file changed

Lines changed: 21 additions & 4 deletions

File tree

‎apps/sim/lib/core/idempotency/claim-faults.integration.ts‎

Lines changed: 21 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,12 @@ class ClaimFaultProxy {
4747
private pipe(client: Socket, upstream: URL): void {
4848
const server = tcpConnect(Number(upstream.port || 6379), upstream.hostname)
4949
let pendingFault: ClaimFault | undefined
50+
// Keeps the stream's tail so a marker that TCP split across chunks still matches.
51+
let tail = ''
5052
client.on('data', (chunk) => {
51-
if (chunk.includes(CLAIM_SCRIPT_MARKER)) {
53+
const seen = tail + chunk.toString('latin1')
54+
tail = seen.slice(-(CLAIM_SCRIPT_MARKER.length - 1))
55+
if (seen.includes(CLAIM_SCRIPT_MARKER)) {
5256
this.claimsForwarded++
5357
if (this.armed) {
5458
pendingFault = this.armed
@@ -86,8 +90,9 @@ describe.runIf(Boolean(redisUrl))('Redis idempotency claim with a lost or late r
8690
const proxy = new ClaimFaultProxy()
8791
let redis: Redis
8892
let direct: Redis
93+
const namespace = `claim-faults-${generateId()}`
8994
const service = new IdempotencyService({
90-
namespace: `claim-faults-${generateId()}`,
95+
namespace,
9196
inProgressTtlSeconds: 60 * 60 * 2,
9297
storeResultBody: false,
9398
forceStorage: 'redis',
@@ -116,6 +121,8 @@ describe.runIf(Boolean(redisUrl))('Redis idempotency claim with a lost or late r
116121

117122
afterAll(async () => {
118123
redis?.disconnect()
124+
const keys = (await direct?.keys(`idempotency:${namespace}:*`)) ?? []
125+
if (keys.length > 0) await direct.del(...keys)
119126
await direct?.quit()
120127
await proxy.stop()
121128
})
@@ -179,15 +186,25 @@ describe.runIf(Boolean(redisUrl))('Redis idempotency claim with a lost or late r
179186

180187
it("still skips a delivery whose key is another holder's live claim", async () => {
181188
const identifier = generateId()
189+
let holderStarted!: () => void
190+
const started = new Promise<void>((resolve) => {
191+
holderStarted = resolve
192+
})
193+
let releaseHolder!: () => void
194+
const released = new Promise<void>((resolve) => {
195+
releaseHolder = resolve
196+
})
182197
const holder = vi.fn(async () => {
183-
await sleep(COMMAND_TIMEOUT_MS)
198+
holderStarted()
199+
await released
184200
return 'holder'
185201
})
186202
const duplicate = vi.fn(async () => 'duplicate')
187203

188204
const running = service.executeOrSkipInProgress('generic', identifier, holder)
189-
await sleep(50)
205+
await started
190206
const second = await service.executeOrSkipInProgress('generic', identifier, duplicate)
207+
releaseHolder()
191208

192209
expect(second).toEqual({ outcome: 'in-progress' })
193210
expect(duplicate).not.toHaveBeenCalled()

0 commit comments

Comments
 (0)