| 495 | } |
| 496 | |
| 497 | private async enqueueSessionMutation<T>( |
| 498 | ids: readonly string[], |
| 499 | operation: () => Promise<T> | T, |
| 500 | ): Promise<T> { |
| 501 | const precedingMutations = ids.map( |
| 502 | (sessionId) => this.sessionMutationTails.get(sessionId) ?? Promise.resolve(), |
| 503 | ); |
| 504 | const preceding = Promise.all(precedingMutations).then(() => undefined); |
| 505 | let complete!: () => void; |
| 506 | const completion = new Promise<void>((resolve) => { |
| 507 | complete = resolve; |
| 508 | }); |
| 509 | const tail = preceding.then(() => completion); |
| 510 | for (const sessionId of ids) this.sessionMutationTails.set(sessionId, tail); |
| 511 | void tail.then(() => { |
| 512 | for (const sessionId of ids) { |
| 513 | if (this.sessionMutationTails.get(sessionId) === tail) { |
| 514 | this.sessionMutationTails.delete(sessionId); |
| 515 | } |
| 516 | } |
| 517 | }); |
| 518 | |
| 519 | try { |
| 520 | await preceding; |
| 521 | return await operation(); |
| 522 | } finally { |
| 523 | complete(); |
| 524 | } |
| 525 | } |
| 526 | |
| 527 | private takeExecutionClaim( |
| 528 | sessionId: string, |