Async Reader-Writer Lock

Coordinate concurrent async readers and exclusive writers with a fair, promise-based reader-writer lock.

TypescriptResilience

Code

snippet
export class AsyncReaderWriterLock {
  private readers = 0;
  private writer = false;
  private queue: Array<{ write: boolean; resolve: () => void }> = [];

  async acquireRead(): Promise<() => void> {
    await this.request(false);
    this.readers += 1;
    return () => this.release(false);
  }

  async acquireWrite(): Promise<() => void> {
    await this.request(true);
    this.writer = true;
    return () => this.release(true);
  }

  private request(write: boolean): Promise<void> {
    if (this.queue.length === 0 && !this.writer && (write || this.readers >= 0)) {
      if (write ? this.readers === 0 : !this.writer) return Promise.resolve();
    }
    return new Promise((resolve) => this.queue.push({ write, resolve }));
  }

  private release(write: boolean) {
    if (write) this.writer = false;
    else this.readers -= 1;
    this.drain();
  }

  private drain() {
    while (this.queue.length > 0) {
      const next = this.queue[0] as { write: boolean; resolve: () => void };
      if (next.write) {
        if (this.writer || this.readers > 0) return;
        (this.queue.shift() as { resolve: () => void }).resolve();
        return;
      }
      (this.queue.shift() as { resolve: () => void }).resolve();
    }
  }
}