@atproto/sync
Version:
atproto sync library
57 lines • 1.96 kB
JavaScript
import PQueue from 'p-queue';
import { ConsecutiveList } from './consecutive-list.js';
// A queue with arbitrarily many partitions, each processing work sequentially.
// Partitions are created lazily and taken out of memory when they go idle.
export class MemoryRunner {
constructor(opts = {}) {
this.opts = opts;
this.consecutive = new ConsecutiveList();
this.partitions = new Map();
this.mainQueue = new PQueue({ concurrency: opts.concurrency ?? Infinity });
this.cursor = opts.startCursor;
}
getCursor() {
return this.cursor;
}
async addTask(partitionId, task) {
if (this.mainQueue.isPaused)
return;
return this.mainQueue.add(() => {
return this.getPartition(partitionId).add(task);
});
}
getPartition(partitionId) {
let partition = this.partitions.get(partitionId);
if (!partition) {
partition = new PQueue({ concurrency: 1 });
partition.once('idle', () => this.partitions.delete(partitionId));
this.partitions.set(partitionId, partition);
}
return partition;
}
async trackEvent(did, seq, handler) {
if (this.mainQueue.isPaused)
return;
const item = this.consecutive.push(seq);
await this.addTask(did, async () => {
await handler();
const latest = item.complete().at(-1);
if (latest !== undefined) {
this.cursor = latest;
if (this.opts.setCursor) {
await this.opts.setCursor(this.cursor);
}
}
});
}
async processAll() {
await this.mainQueue.onIdle();
}
async destroy() {
this.mainQueue.pause();
this.mainQueue.clear();
this.partitions.forEach((p) => p.clear());
await this.mainQueue.onIdle();
}
}
//# sourceMappingURL=memory-runner.js.map