Skip to content

Commit 8197bc2

Browse files
authored
Merge pull request #268 from deploystackio/feat/metrics
Feat/metrics
2 parents 8ef7b9f + 39c3279 commit 8197bc2

File tree

13 files changed

+1524
-142
lines changed

13 files changed

+1524
-142
lines changed

development/backend/cron.mdx

Lines changed: 230 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,230 @@
1+
---
2+
title: Cron Job Scheduling
3+
description: Schedule recurring background tasks using cron expressions with the DeployStack job queue system.
4+
sidebarTitle: Cron
5+
---
6+
7+
# Cron Job Scheduling
8+
9+
DeployStack includes a cron job scheduling system that integrates seamlessly with the [Background Job Queue](/development/backend/job-queue). This allows you to schedule recurring tasks using standard cron expressions, with all the benefits of the job queue system including persistence, retries, and monitoring.
10+
11+
## Architecture
12+
13+
The cron system follows a two-tier architecture:
14+
15+
1. **Cron Scheduler**: Uses `node-cron` to schedule tasks based on cron expressions
16+
2. **Job Queue**: Processes the actual work with persistence and retry capabilities
17+
18+
```
19+
Cron Expression → Scheduler fires → Creates job in queue → Worker processes job
20+
```
21+
22+
This separation provides:
23+
- **Reliability**: Jobs persist even if the server restarts
24+
- **Visibility**: All jobs are logged and trackable in the database
25+
- **Rate Limiting**: Built-in queue management prevents system overload
26+
- **Monitoring**: Track success/failure rates and execution history
27+
28+
## Creating a Cron Job
29+
30+
### Step 1: Define the Cron Job
31+
32+
Create a new file in `src/cron/jobs/`:
33+
34+
```typescript
35+
// src/cron/jobs/dailyCleanup.ts
36+
import type { CronJob } from '../cronManager';
37+
import type { JobQueueService } from '../../services/jobQueueService';
38+
39+
export function createDailyCleanupJob(jobQueueService: JobQueueService): CronJob {
40+
return {
41+
name: 'daily-cleanup',
42+
schedule: '0 2 * * *', // Every day at 2 AM
43+
44+
task: async () => {
45+
await jobQueueService.createJob('cleanup_old_data', {
46+
daysToKeep: 30
47+
});
48+
}
49+
};
50+
}
51+
```
52+
53+
### Step 2: Create the Worker
54+
55+
Create a worker to process the job in `src/workers/`:
56+
57+
```typescript
58+
// src/workers/cleanupWorker.ts
59+
import type { AnyDatabase } from '../db';
60+
import type { FastifyBaseLogger } from 'fastify';
61+
import type { Worker, WorkerResult } from './types';
62+
63+
interface CleanupPayload {
64+
daysToKeep: number;
65+
}
66+
67+
export class CleanupWorker implements Worker {
68+
constructor(
69+
private readonly db: AnyDatabase,
70+
private readonly logger: FastifyBaseLogger
71+
) {}
72+
73+
async execute(payload: unknown, jobId: string): Promise<WorkerResult> {
74+
const { daysToKeep } = payload as CleanupPayload;
75+
76+
this.logger.info({
77+
jobId,
78+
daysToKeep,
79+
operation: 'cleanup_old_data'
80+
}, 'Starting cleanup job');
81+
82+
try {
83+
// Your cleanup logic here
84+
const cutoffDate = new Date();
85+
cutoffDate.setDate(cutoffDate.getDate() - daysToKeep);
86+
87+
// Example: Delete old records
88+
// const result = await this.db.delete(oldRecordsTable)
89+
// .where(lt(oldRecordsTable.createdAt, cutoffDate));
90+
91+
this.logger.info({
92+
jobId,
93+
operation: 'cleanup_old_data'
94+
}, 'Cleanup completed successfully');
95+
96+
return {
97+
success: true,
98+
message: 'Cleanup completed successfully'
99+
};
100+
} catch (error) {
101+
this.logger.error({ jobId, error }, 'Cleanup job failed');
102+
throw error; // Triggers retry logic
103+
}
104+
}
105+
}
106+
```
107+
108+
### Step 3: Register the Worker
109+
110+
Add the worker to `src/workers/index.ts`:
111+
112+
```typescript
113+
import { CleanupWorker } from './cleanupWorker';
114+
115+
export function registerWorkers(
116+
processor: JobProcessorService,
117+
db: AnyDatabase,
118+
logger: FastifyBaseLogger
119+
): void {
120+
// ... existing workers ...
121+
122+
processor.registerWorker(
123+
'cleanup_old_data',
124+
new CleanupWorker(db, logger)
125+
);
126+
}
127+
```
128+
129+
### Step 4: Register the Cron Job
130+
131+
Add the cron job to `src/cron/index.ts`:
132+
133+
```typescript
134+
import { createDailyCleanupJob } from './jobs/dailyCleanup';
135+
136+
export function initializeCronJobs(
137+
jobQueueService: JobQueueService,
138+
logger: FastifyBaseLogger
139+
): CronManager {
140+
const cronManager = new CronManager(logger);
141+
142+
cronManager.register(createDailyCleanupJob(jobQueueService));
143+
144+
return cronManager;
145+
}
146+
```
147+
148+
## Cron Expression Syntax
149+
150+
The system uses standard cron syntax with 5 or 6 fields:
151+
152+
```
153+
┌────────────── second (optional, 0-59)
154+
│ ┌──────────── minute (0-59)
155+
│ │ ┌────────── hour (0-23)
156+
│ │ │ ┌──────── day of month (1-31)
157+
│ │ │ │ ┌────── month (1-12)
158+
│ │ │ │ │ ┌──── day of week (0-7, 0 or 7 = Sunday)
159+
│ │ │ │ │ │
160+
* * * * * *
161+
```
162+
163+
### Common Examples
164+
165+
```typescript
166+
'*/2 * * * *' // Every 2 minutes
167+
'0 * * * *' // Every hour (at minute 0)
168+
'0 0 * * *' // Daily at midnight
169+
'0 2 * * *' // Daily at 2 AM
170+
'0 9 * * 1-5' // Weekdays at 9 AM
171+
'*/30 * * * *' // Every 30 minutes
172+
'0 */6 * * *' // Every 6 hours
173+
'0 0 1 * *' // First day of every month
174+
'0 0 * * 0' // Every Sunday at midnight
175+
```
176+
177+
## Integration with Job Queue
178+
179+
The cron system is designed to work with the job queue system. This provides several benefits:
180+
181+
**Persistence**: Jobs created by cron are stored in the database and survive server restarts.
182+
183+
**Retry Logic**: Failed jobs are automatically retried with exponential backoff.
184+
185+
**Rate Limiting**: The job queue processes jobs sequentially, preventing system overload.
186+
187+
**Monitoring**: Track job execution history, success rates, and failures.
188+
189+
For more details on the job queue system, see the [Background Job Queue](/development/backend/job-queue) documentation.
190+
191+
## Example: Complete Implementation
192+
193+
Here's a complete example showing how to create a cron job that sends a daily email digest:
194+
195+
```typescript
196+
// src/cron/jobs/dailyDigest.ts
197+
import type { CronJob } from '../cronManager';
198+
import type { JobQueueService } from '../../services/jobQueueService';
199+
200+
export function createDailyDigestJob(jobQueueService: JobQueueService): CronJob {
201+
return {
202+
name: 'daily-digest-email',
203+
schedule: '0 8 * * *', // Every day at 8 AM
204+
205+
task: async () => {
206+
// Create job to send digest email
207+
await jobQueueService.createJob('send_email', {
208+
209+
subject: 'Daily Activity Digest',
210+
template: 'daily_digest',
211+
variables: {
212+
date: new Date().toISOString().split('T')[0]
213+
}
214+
});
215+
}
216+
};
217+
}
218+
```
219+
220+
The `send_email` worker (already registered in the system) will process this job using the existing [Email System](/development/backend/mail).
221+
222+
## Lifecycle Management
223+
224+
The cron system is automatically initialized during server startup and gracefully shut down when the server stops:
225+
226+
**Startup**: All registered cron jobs are scheduled and begin running according to their expressions.
227+
228+
**Shutdown**: When the server receives a shutdown signal, cron jobs stop creating new jobs, allowing the job queue to finish processing existing jobs.
229+
230+
This ensures no jobs are lost during server restarts or deployments.

development/backend/index.mdx

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,14 @@ The development server starts at `http://localhost:3000` with API documentation
112112
Database-backed job processing system with persistent storage, automatic retries, and rate limiting for long-running background tasks.
113113
</Card>
114114

115+
<Card
116+
icon="clock"
117+
href="/development/backend/cron"
118+
title="Cron Job Scheduling"
119+
>
120+
Schedule recurring background tasks using cron expressions integrated with the job queue system.
121+
</Card>
122+
115123
<Card
116124
icon="terminal"
117125
href="/development/backend/satellite/events"

0 commit comments

Comments
 (0)