readd queue-worker domain, add heartbewat to db-queue
This commit is contained in:
1 parent
ae4c433246
commit
90bbc764fc
7 files changed
+113
-2
No files matched your search
@@ -0,0 +1,22 @@
|
||||
import { Schema, model } from "mongoose";
|
||||
import { QueueModes } from "@/domain/app-settings/app-settings.type.js";
|
||||
import { QueueWorkerDocument } from "@/domain/queue-workers/queue-worker.type.js";
|
||||
|
||||
// Single source of truth for worker liveness: the TTL that GCs stale records and
|
||||
// the window readers use to count a worker as alive. Heartbeat cadence must stay well below it.
|
||||
export const WORKER_TTL_SECONDS = 180;
|
||||
|
||||
const QueueWorkerSchema = new Schema<QueueWorkerDocument>(
|
||||
{
|
||||
_id: { type: String, required: true },
|
||||
mode: { type: String, enum: QueueModes, required: true },
|
||||
lastSeenAt: { type: Date, default: Date.now, expires: WORKER_TTL_SECONDS },
|
||||
},
|
||||
{ timestamps: true }
|
||||
);
|
||||
|
||||
const QueueWorkerModel = model<QueueWorkerDocument>("QueueWorker", QueueWorkerSchema);
|
||||
|
||||
export type { QueueWorkerDocument };
|
||||
export { QueueWorkerModel };
|
||||
export default QueueWorkerModel;
|
||||
@@ -0,0 +1,8 @@
|
||||
import type { QueueMode } from "@/domain/app-settings/app-settings.type.js";
|
||||
import type { QueueWorker } from "@/domain/queue-workers/queue-worker.type.js";
|
||||
|
||||
export interface IQueueWorkersRepository {
|
||||
upsert(workerId: string, mode: QueueMode): Promise<void>;
|
||||
findRecent(maxAgeMs: number): Promise<QueueWorker[]>;
|
||||
deleteById(workerId: string): Promise<void>;
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
import type { QueueMode } from "@/domain/app-settings/app-settings.type.js";
|
||||
import type { IQueueWorkersRepository } from "./queue-worker.repository.interface.js";
|
||||
import type { QueueWorker } from "@/domain/queue-workers/queue-worker.type.js";
|
||||
import { QueueWorkerModel, type QueueWorkerDocument } from "@/domain/queue-workers/queue-worker.model.js";
|
||||
const SERVICE_NAME = "MongoQueueWorkersRepository";
|
||||
|
||||
class MongoQueueWorkersRepository implements IQueueWorkersRepository {
|
||||
static SERVICE_NAME = SERVICE_NAME;
|
||||
|
||||
protected toEntity = (doc: QueueWorkerDocument): QueueWorker => {
|
||||
return {
|
||||
workerId: doc._id,
|
||||
mode: doc.mode,
|
||||
lastSeenAt: doc.lastSeenAt.getTime(),
|
||||
};
|
||||
};
|
||||
|
||||
upsert = async (workerId: string, mode: QueueMode): Promise<void> => {
|
||||
await QueueWorkerModel.updateOne({ _id: workerId }, { $set: { mode, lastSeenAt: new Date() } }, { upsert: true });
|
||||
};
|
||||
|
||||
findRecent = async (maxAgeMs: number): Promise<QueueWorker[]> => {
|
||||
const cutoff = new Date(Date.now() - maxAgeMs);
|
||||
const docs = await QueueWorkerModel.find({ lastSeenAt: { $gte: cutoff } });
|
||||
return docs.map(this.toEntity);
|
||||
};
|
||||
|
||||
deleteById = async (workerId: string): Promise<void> => {
|
||||
await QueueWorkerModel.deleteOne({ _id: workerId });
|
||||
};
|
||||
}
|
||||
|
||||
export default MongoQueueWorkersRepository;
|
||||
@@ -0,0 +1,18 @@
|
||||
import { type QueueMode } from "@/domain/app-settings/app-settings.type.js";
|
||||
|
||||
// Heartbeat presence record for a scheduler instance. _id is the scheduler's
|
||||
// workerId (hostname:pid:uuid). The TTL index on lastSeenAt garbage-collects
|
||||
// records for instances that have stopped heartbeating.
|
||||
export interface QueueWorkerDocument {
|
||||
_id: string;
|
||||
mode: QueueMode;
|
||||
lastSeenAt: Date;
|
||||
createdAt: Date;
|
||||
updatedAt: Date;
|
||||
}
|
||||
|
||||
export type QueueWorker = {
|
||||
workerId: string; // hostname:pid:uuid
|
||||
mode: QueueMode;
|
||||
lastSeenAt: number; // epoch ms of the last heartbeat
|
||||
};
|
||||
Reference in new issue
Block a user