111 lines
3.2 KiB
Markdown
111 lines
3.2 KiB
Markdown
# @internal/schedule-engine
|
|
|
|
The `@internal/schedule-engine` package encapsulates all scheduling logic for Trigger.dev, providing a clean API boundary for managing scheduled tasks and their execution.
|
|
|
|
## Architecture
|
|
|
|
The ScheduleEngine follows the same pattern as the RunEngine, providing:
|
|
|
|
- **Centralized Schedule Management**: All schedule-related operations go through the ScheduleEngine
|
|
- **Redis Worker Integration**: Built-in Redis-based distributed task scheduling
|
|
- **Distributed Execution**: Prevents thundering herd issues by distributing executions across time windows
|
|
- **Comprehensive Testing**: Built-in utilities for testing schedule behavior
|
|
|
|
## Key Components
|
|
|
|
### ScheduleEngine Class
|
|
|
|
The main interface for all schedule operations:
|
|
|
|
```typescript
|
|
import { ScheduleEngine } from "@internal/schedule-engine";
|
|
|
|
const engine = new ScheduleEngine({
|
|
prisma,
|
|
redis: {
|
|
/* Redis configuration */
|
|
},
|
|
worker: {
|
|
/* Worker configuration */
|
|
},
|
|
distributionWindow: { seconds: 30 }, // Optional: default 30s
|
|
});
|
|
|
|
// Register next schedule instance
|
|
await engine.registerNextTaskScheduleInstance({ instanceId });
|
|
|
|
// Upsert a schedule
|
|
await engine.upsertTaskSchedule({
|
|
projectId,
|
|
schedule: {
|
|
taskIdentifier: "my-task",
|
|
cron: "0 */5 * * *",
|
|
timezone: "UTC",
|
|
environments: ["env-1", "env-2"],
|
|
},
|
|
});
|
|
```
|
|
|
|
### Distributed Scheduling
|
|
|
|
The engine includes built-in distributed scheduling to prevent all scheduled tasks from executing at exactly the same moment:
|
|
|
|
```typescript
|
|
import { calculateDistributedExecutionTime } from "@internal/schedule-engine";
|
|
|
|
const exactTime = new Date("2024-01-01T12:00:00Z");
|
|
const distributedTime = calculateDistributedExecutionTime(exactTime, 30); // 30-second window
|
|
```
|
|
|
|
### Schedule Calculation
|
|
|
|
High-performance CRON schedule calculation with optimization for old timestamps:
|
|
|
|
```typescript
|
|
import {
|
|
calculateNextScheduledTimestampFromNow,
|
|
nextScheduledTimestamps,
|
|
} from "@internal/schedule-engine";
|
|
|
|
const nextRun = calculateNextScheduledTimestampFromNow("0 */5 * * *", "UTC");
|
|
const upcoming = nextScheduledTimestamps("0 */5 * * *", "UTC", nextRun, 5);
|
|
```
|
|
|
|
## Integration with Webapp
|
|
|
|
The ScheduleEngine should be the **API boundary** between the webapp and schedule logic. Services in the webapp should call into the ScheduleEngine rather than implementing schedule logic directly.
|
|
|
|
### Migration Path
|
|
|
|
Currently, the webapp uses individual services like:
|
|
|
|
- `RegisterNextTaskScheduleInstanceService`
|
|
- `TriggerScheduledTaskService`
|
|
- Schedule calculation utilities
|
|
|
|
These should be replaced with ScheduleEngine method calls:
|
|
|
|
```typescript
|
|
// Old approach
|
|
const service = new RegisterNextTaskScheduleInstanceService(tx);
|
|
await service.call(instanceId);
|
|
|
|
// New approach
|
|
await scheduleEngine.registerNextTaskScheduleInstance({ instanceId });
|
|
```
|
|
|
|
## Configuration
|
|
|
|
The ScheduleEngine expects these configuration options:
|
|
|
|
- `prisma`: PrismaClient instance
|
|
- `redis`: Redis connection configuration
|
|
- `worker`: Worker configuration (concurrency, polling intervals)
|
|
- `distributionWindow`: Optional time window for distributed execution
|
|
- `tracer`: Optional OpenTelemetry tracer
|
|
- `meter`: Optional OpenTelemetry meter
|
|
|
|
## Testing
|
|
|
|
The package includes comprehensive test utilities and examples. See the test directory for usage examples.
|