Cleanup terminology

This commit is contained in:
Dominic Ferrando
2026-07-12 01:43:55 -04:00
parent 80f8962a3b
commit 8b81156f6c
4 changed files with 46 additions and 37 deletions
+23 -17
View File
@@ -9,9 +9,9 @@ import type { TSchema } from "@sinclair/typebox";
export type EventType = "product_sync" | "product_order_created" /* TODO: more events... */;
export type EventSource = "portal" | "printful" | "webflow";
type EventHandler<Payload extends JsonValue, State extends JsonValue> =
type EventProcessor<Payload extends JsonValue, State extends JsonValue> =
(id: string, payload: Payload, setState: (state: State) => Promise<void>) => Promise<void>;
type EventStatus = "queued" | "active" | "failed" | "fulfilled";
type EventStatus = "pending" | "processing" | "failed" | "fulfilled";
class AlreadyClaimedEventError extends Error { }
class ConcurrencyLimitReachedError extends Error { }
@@ -32,19 +32,22 @@ type EventQueueServiceOptions<Payload extends JsonValue, State extends JsonValue
timeoutMs: number,
},
},
handler: EventHandler<Payload, State>,
processor: EventProcessor<Payload, State>,
}
export class EventQueueService<Payload extends JsonValue, State extends JsonValue> {
private _lastCleanDate: Date = new Date(0);
readonly cfg: EventQueueServiceOptions<Payload, State>["cfg"];
constructor(private opt: EventQueueServiceOptions<Payload, State>) { }
constructor(private readonly opt: EventQueueServiceOptions<Payload, State>) {
this.cfg = opt.cfg;
}
get lastCleanDate() { return this._lastCleanDate; };
static status(event: Pick<Selectable<DB["events"]>, "started_at" | "ended_at" | "has_failed">): EventStatus {
if (!event.started_at) return "queued";
if (!event.ended_at) return "active";
if (!event.started_at) return "pending";
if (!event.ended_at) return "processing";
return event.has_failed ? "failed" : "fulfilled";
}
@@ -143,17 +146,20 @@ export class EventQueueService<Payload extends JsonValue, State extends JsonValu
}
async clean() {
// Find and fail any timed out active events
const activeEvents = await this.activeEvents();
for (const activeEvent of activeEvents) {
const activeEventTimedOut = (Date.now() - (activeEvent.started_at?.getTime() ?? 0) > this.opt.cfg.concurrency.timeoutMs);
if (activeEventTimedOut) {
log.warn({ name: activeEvent.id }, "active event has timed out. failing it and continuing...");
await this.fail(activeEvent.id);
try {
// Find and fail any timed out processing events
const processingEvents = await this.processingEvents();
for (const processingEvent of processingEvents) {
const processingEventTimedOut = (Date.now() - (processingEvent.started_at?.getTime() ?? 0) > this.opt.cfg.concurrency.timeoutMs);
if (processingEventTimedOut) {
log.warn({ name: processingEvent.id }, "processing event has timed out. failing it and continuing...");
await this.fail(processingEvent.id);
}
}
}
this._lastCleanDate = new Date();
finally {
this._lastCleanDate = new Date();
}
}
async front(trx?: Transaction<DB>) {
@@ -167,7 +173,7 @@ export class EventQueueService<Payload extends JsonValue, State extends JsonValu
return result;
}
async activeEvents(trx?: Transaction<DB>) {
async processingEvents(trx?: Transaction<DB>) {
return await (trx ?? db).selectFrom("events")
.select(["started_at", "id"])
.where("type", "=", this.opt.type)
@@ -180,7 +186,7 @@ export class EventQueueService<Payload extends JsonValue, State extends JsonValu
log.info({ id, payload }, "handling event");
try {
Value.Assert(this.opt.schemas.payload, payload);
await this.opt.handler(id, payload, async (state) => {
await this.opt.processor(id, payload, async (state) => {
await db.updateTable("events")
.set({ state })
.where("id", "=", id)