fix(core): coalesce queued compactions (#43292)

This commit is contained in:
Kit Langton 2026-08-18 17:04:02 -04:00 committed by GitHub
parent 511b4556a2
commit 5ff6bb87cf
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 39 additions and 10 deletions

View file

@ -180,13 +180,27 @@ export const admitCompaction = Effect.fn("SessionInbox.admitCompaction")(functio
bus: Bus.Interface,
input: { readonly id: SessionMessage.ID; readonly sessionID: SessionSchema.ID; readonly delivery: Delivery },
) {
const admitted = yield* admit(db, bus, {
id: input.id,
sessionID: input.sessionID,
item: Item.make({ type: "compaction", payload: {}, delivery: input.delivery }),
})
if (admitted.type === "compaction") return admitted
return yield* Effect.die(new LifecycleConflict({ id: input.id }))
return yield* serialized(
input.sessionID,
Effect.gen(function* () {
const exact = yield* find(db, input.id)
if (exact) {
if (exact.type === "compaction" && exact.sessionID === input.sessionID) return exact
return yield* Effect.die(new LifecycleConflict({ id: input.id }))
}
if (yield* promotedFromMessage(db, input.sessionID, input.id, input.delivery))
return yield* Effect.die(new LifecycleConflict({ id: input.id }))
const pending = (yield* list(db, input.sessionID)).find((item) => item.type === "compaction")
if (pending) return pending
const admitted = yield* admit(db, bus, {
id: input.id,
sessionID: input.sessionID,
item: Item.make({ type: "compaction", payload: {}, delivery: input.delivery }),
})
if (admitted.type === "compaction") return admitted
return yield* Effect.die(new LifecycleConflict({ id: input.id }))
}),
)
})
export const projectAdmitted = Effect.fn("SessionInbox.projectAdmitted")(function* (

View file

@ -73,7 +73,7 @@ const it = testEffect(
)
describe("Session.compact", () => {
it.effect("durably stacks manual compaction", () =>
it.effect("durably coalesces manual compaction", () =>
Effect.gen(function* () {
requests = []
const session = yield* Session.Service
@ -102,11 +102,10 @@ describe("Session.compact", () => {
const first = yield* session.compact({ sessionID: created.id })
const second = yield* session.compact({ sessionID: created.id })
expect(second.id).not.toBe(first.id)
expect(second.id).toBe(first.id)
expect(requests).toHaveLength(0)
expect(yield* session.inbox(created.id)).toEqual([
expect.objectContaining({ id: first.id, type: "compaction", delivery: "queue" }),
expect.objectContaining({ id: second.id, type: "compaction", delivery: "queue" }),
])
expect((yield* session.context(created.id)).find((message) => message.id === first.id)).toBeUndefined()
@ -115,4 +114,20 @@ describe("Session.compact", () => {
expect(steer).toMatchObject({ type: "compaction", delivery: "steer" })
}),
)
it.effect("coalesces concurrent manual compaction", () =>
Effect.gen(function* () {
const session = yield* Session.Service
const created = yield* session.create({ location })
const admitted = yield* Effect.all(
[SessionMessage.ID.create(), SessionMessage.ID.create()].map((id) =>
session.compact({ id, sessionID: created.id }),
),
{ concurrency: "unbounded" },
)
expect(admitted[1]?.id).toBe(admitted[0]?.id)
expect(yield* session.inbox(created.id)).toHaveLength(1)
}),
)
})