Extending Background
Background is designed with extensibility in mind, allowing you to create custom implementations tailored to your specific requirements.
Core Design Principles
Background follows object-oriented design principles. When extending its functionality, it's recommended to maintain these principles in your custom implementations.
Key OOP Concepts
To effectively extend Background, familiarity with these concepts is essential:
- Inheritance: Creating new classes based on existing ones
- Polymorphism: Implementing interfaces with various concrete implementations
- Encapsulation: Controlling access to class components through access modifiers
The JobQueue Class
The JobQueue
class serves as the foundation for all queue implementations in Background. When creating custom queues, you'll extend this class and work with its:
- Protected properties
- Protected methods
- Storage implementation patterns
The class interacts with storage implementations that follow the JobStorage
interface.
JobStorage Interface
export interface JobStorage {
saveJob(job: Job): Promise<void>;
getJob(id: string): Promise<Job | null>;
getJobsByStatus(status: JobStatus): Promise<Job[]>;
updateJob(job: Job): Promise<void>;
acquireNextJob(): Promise<Job | null>;
completeJob(jobId: string, result: any): Promise<void>;
failJob(jobId: string, error: string): Promise<void>;
}
Extending the Storage Interface
You can extend the base JobStorage
interface to add specialized functionality:
export interface RedisStorage extends JobStorage {
// Atomic job acquisition with optional time-to-live
acquireNextJob(ttl?: number): Promise<Job | null>;
// Retrieve jobs by priority level
getJobsByPriority(priority: number): Promise<Job[]>;
// Get scheduled jobs within a specified time range
getScheduledJobs(startTime: Date, endTime?: Date): Promise<Job[]>;
// Remove all jobs from storage
clear(): Promise<void>;
}
Creating Custom Queues
Implementation Steps
- Create a class that extends
JobQueue
- Initialize storage and configuration in the constructor
- Call the parent constructor using
super()
- Override key methods to customize behavior
Required Overrides
At minimum, you'll typically need to override these methods:
protected async processNextBatch(): Promise<void>
protected async processJob(job: Job): Promise<void>
Implement additional private methods as needed for your specific implementation.
Job Interface Reference
Here's the complete Job
interface for reference:
// Job status types
export type JobStatus = "pending" | "processing" | "completed" | "failed";
// Job interface
export interface Job<T = any> {
id: string;
name: string;
data: T;
status: JobStatus;
createdAt: Date;
scheduledAt?: Date;
startedAt?: Date;
completedAt?: Date;
error?: string;
priority?: number;
result?: any;
retryCount?: number;
repeat?: {
every?: number;
unit?: "seconds" | "minutes" | "hours" | "days" | "weeks" | "months";
startDate?: Date;
endDate?: Date;
limit?: number;
};
}
// Job handler type
export type JobHandler<T = any, R = any> = (data: T) => Promise<R>;
Best Practices
- Review the source code before implementing custom extensions
- Maintain consistent error handling patterns
- Follow the existing architectural patterns where possible
- Document custom implementations thoroughly
Source Code Reference
For a deeper understanding of Background internals, refer to the GitHub Repository.