@backgroundjs/core
Version:
An extendible background job queue for js/ts applications
133 lines (118 loc) • 3.58 kB
text/typescript
import { Job, JobStatus } from "../types";
import { JobStorage } from "./base-storage";
export class InMemoryJobStorage implements JobStorage {
private jobs: Map<string, Job> = new Map();
private logging: boolean = false;
constructor(options?: { logging?: boolean }) {
this.logging = options?.logging || false;
}
async saveJob(job: Job): Promise<void> {
try {
this.jobs.set(job.id, job);
} catch (error) {
if (this.logging) {
console.error(`[InMemoryJobStorage] Error saving job:`, error);
}
}
}
async getJob(id: string): Promise<Job | null> {
try {
return this.jobs.get(id) || null;
} catch (error) {
if (this.logging) {
console.error(`[InMemoryJobStorage] Error getting job:`, error);
}
return null;
}
}
async getJobsByStatus(status: JobStatus): Promise<Job[]> {
try {
return Array.from(this.jobs.values()).filter(
(job) => job.status === status,
);
} catch (error) {
if (this.logging) {
console.error(
`[InMemoryJobStorage] Error getting jobs by status:`,
error,
);
}
return [];
}
}
async updateJob(job: Job): Promise<void> {
try {
if (!this.jobs.has(job.id)) {
throw new Error(`Job with id ${job.id} not found`);
}
this.jobs.set(job.id, job);
} catch (error) {
if (this.logging) {
console.error(`[InMemoryJobStorage] Error updating job:`, error);
}
}
}
async acquireNextJob(): Promise<Job | null> {
try {
// First, filter to get eligible jobs
const pendingJobs = Array.from(this.jobs.values()).filter((job) => {
if (job.status !== "pending") return false;
if (job.scheduledAt) {
const now = new Date();
return job.scheduledAt <= now;
}
return true;
});
const sortedJobs = pendingJobs.sort((a, b) => {
const priorityA = a.priority || 10;
const priorityB = b.priority || 10;
if (priorityA !== priorityB) {
return priorityA - priorityB;
}
return a.createdAt.getTime() - b.createdAt.getTime();
});
const job = sortedJobs[0];
if (!job) return null;
job.status = "processing";
job.startedAt = new Date();
// Store the updated job
this.jobs.set(job.id, job);
return job;
} catch (error) {
if (this.logging) {
console.error(`[InMemoryJobStorage] Error acquiring next job:`, error);
}
return null;
}
}
async completeJob(jobId: string, result: any): Promise<void> {
try {
const job = await this.getJob(jobId);
if (!job) {
throw new Error(`Job with id ${jobId} not found`);
}
job.status = "completed";
job.result = result;
await this.updateJob(job);
} catch (error) {
if (this.logging) {
console.error(`[InMemoryJobStorage] Error completing job:`, error);
}
}
}
async failJob(jobId: string, error: string): Promise<void> {
try {
const job = await this.getJob(jobId);
if (!job) {
throw new Error(`Job with id ${jobId} not found`);
}
job.status = "failed";
job.error = error;
await this.updateJob(job);
} catch (error) {
if (this.logging) {
console.error(`[InMemoryJobStorage] Error failing job:`, error);
}
}
}
}