SPB Git

Repository Public MIT Selected

semaphore.mjs 1.9 KB 64 lines javascript

1/**2 * ─────────────────────────────────────────────3 *  SPB Git — Personal Git Platform4 * ─────────────────────────────────────────────5 *  Author  : Simon-Pierre Boucher6 *  Contact : contact@spboucher.ai7 *  File    : src/lib/semaphore.mjs8 *  Purpose : Tiny counting semaphore — bounds concurrent git subprocesses so crawlers cannot exhaust memory9 *  License : MIT © Simon-Pierre Boucher10 * ─────────────────────────────────────────────11 */1213/**14 * Counting semaphore. `acquire()` resolves with a release function; callers15 * must release in a `finally`. Waiters are served in FIFO order.16 */17export class Semaphore {18  /** @param {number} limit maximum concurrent holders */19  constructor(limit) {20    this.limit = Math.max(1, limit | 0);21    this.active = 0;22    this.queue = [];23  }2425  /** @returns {Promise<() => void>} release function */26  acquire() {27    return new Promise((resolve) => {28      const grant = () => {29        this.active += 1;30        let released = false;31        resolve(() => {32          if (released) return;33          released = true;34          this.active -= 1;35          const next = this.queue.shift();36          if (next) next();37        });38      };39      if (this.active < this.limit) grant();40      else this.queue.push(grant);41    });42  }4344  /**45   * Run `fn` while holding one slot.46   * @template T47   * @param {() => Promise<T>} fn48   * @returns {Promise<T>}49   */50  async run(fn) {51    const release = await this.acquire();52    try {53      return await fn();54    } finally {55      release();56    }57  }5859  /** @returns {{active: number, waiting: number, limit: number}} */60  stats() {61    return { active: this.active, waiting: this.queue.length, limit: this.limit };62  }63}64
Files main
Menu

Theme