UNPKG

@atproto/ozone

Version:

Backend service for moderating the Bluesky network.

111 lines 3.85 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.StrikeExpiryProcessor = void 0; const common_1 = require("@atproto/common"); const logger_1 = require("../logger"); const JOB_NAME = 'strike_expiry'; class StrikeExpiryProcessor { constructor(db, strikeServiceCreator) { Object.defineProperty(this, "db", { enumerable: true, configurable: true, writable: true, value: db }); Object.defineProperty(this, "strikeServiceCreator", { enumerable: true, configurable: true, writable: true, value: strikeServiceCreator }); Object.defineProperty(this, "destroyed", { enumerable: true, configurable: true, writable: true, value: false }); Object.defineProperty(this, "processingPromise", { enumerable: true, configurable: true, writable: true, value: Promise.resolve() }); Object.defineProperty(this, "timer", { enumerable: true, configurable: true, writable: true, value: void 0 }); } start() { this.initializeCursor().then(() => this.poll()); } poll() { if (this.destroyed) return; this.processingPromise = this.processExpiredStrikes() .catch((err) => logger_1.dbLogger.error({ err }, 'strike expiry processing errored')) .finally(() => { this.timer = setTimeout(() => this.poll(), getInterval()); }); } async destroy() { this.destroyed = true; if (this.timer) { clearTimeout(this.timer); this.timer = undefined; } await this.processingPromise; } async initializeCursor() { await this.db.db .insertInto('job_cursor') .values({ job: JOB_NAME, cursor: null, }) .onConflict((oc) => oc.doNothing()) .execute(); } async getCursor() { const entry = await this.db.db .selectFrom('job_cursor') .select('cursor') .where('job', '=', JOB_NAME) .executeTakeFirst(); return entry?.cursor || null; } async updateCursor(cursor) { await this.db.db .updateTable('job_cursor') .set({ cursor }) .where('job', '=', JOB_NAME) .execute(); } async processExpiredStrikes() { const now = new Date(); const strikeService = this.strikeServiceCreator(this.db); const lastProcessedAt = await this.getCursor(); const affectedSubjects = await strikeService.getExpiredStrikeSubjects(lastProcessedAt || undefined); if (!affectedSubjects.length) { logger_1.dbLogger.info('no expired strikes to process'); await this.updateCursor(now.toISOString()); return; } logger_1.dbLogger.info({ count: affectedSubjects.length }, 'processing subjects with expired strikes'); await Promise.all(affectedSubjects.map(({ subjectDid }) => { return strikeService.updateSubjectStrikeCount(subjectDid); })); await this.updateCursor(now.toISOString()); logger_1.dbLogger.info({ processed: affectedSubjects.length }, 'strike expiry processing completed'); } } exports.StrikeExpiryProcessor = StrikeExpiryProcessor; const getInterval = () => { // Run every hour, synchronized to the hour boundary const now = Date.now(); const intervalMs = common_1.HOUR; const nextIteration = Math.ceil(now / intervalMs); return nextIteration * intervalMs - now; }; //# sourceMappingURL=strike-expiry-processor.js.map