Besides using the scheduler:run command, you can manually initialize and control the scheduler worker in your code. This approach is useful when you need fine-grained control over the scheduler lifecycle or want to embed the scheduler in a custom application.
Using the Worker class
The Worker class allows you to programmatically start and stop the scheduler:
import { Worker } from 'adonisjs-scheduler'
import app from '@adonisjs/core/services/app'
const worker = new Worker(app)
app.terminating(async () => {
await worker.stop()
})
await worker.start()
This gives you direct control over when the scheduler starts and stops, without relying on the CLI command.
When to use this approach
Consider using the manual worker approach when:
Embedding in a web server
You want to run the scheduler alongside your HTTP server in the same process:
import { Worker } from 'adonisjs-scheduler'
import app from '@adonisjs/core/services/app'
// Start the scheduler
const worker = new Worker(app)
await worker.start()
// Graceful shutdown
app.terminating(async () => {
await worker.stop()
})
Custom initialization logic
You need to perform custom setup before starting the scheduler:
import { Worker } from 'adonisjs-scheduler'
import app from '@adonisjs/core/services/app'
import redis from '@adonisjs/redis/services/main'
// Perform health checks
await redis.ping()
// Initialize worker
const worker = new Worker(app)
await worker.start()
Running multiple workers
You want to run multiple scheduler workers with different tags in the same process:
import { Worker } from 'adonisjs-scheduler'
import app from '@adonisjs/core/services/app'
const reportsWorker = new Worker(app)
const maintenanceWorker = new Worker(app)
await reportsWorker.start('reports')
await maintenanceWorker.start('maintenance')
app.terminating(async () => {
await Promise.all([
reportsWorker.stop(),
maintenanceWorker.stop(),
])
})
Testing
You need to control the scheduler lifecycle during testing:
import { test } from '@japa/runner'
import { Worker } from 'adonisjs-scheduler'
import app from '@adonisjs/core/services/app'
test.group('Scheduler', (group) => {
let worker: Worker
group.setup(async () => {
worker = new Worker(app)
await worker.start()
})
group.teardown(async () => {
await worker.stop()
})
test('executes scheduled tasks', async () => {
// Test logic
})
})
Configuration for manual worker
When using the manual worker approach, you need to configure your adonisrc.ts to load the scheduler provider in the appropriate environments.
Include specific environments
Specify which environments should load the scheduler:
import { defineConfig } from '@adonisjs/core/app'
export default defineConfig({
providers: [
{
file: () => import('adonisjs-scheduler/scheduler_provider'),
environment: ['console', 'web'],
},
],
})
This configuration loads the scheduler in both:
console - When running Ace commands
web - When running the HTTP server
Enable for all environments
Alternatively, enable the scheduler provider globally:
import { defineConfig } from '@adonisjs/core/app'
export default defineConfig({
providers: [
() => import('adonisjs-scheduler/scheduler_provider'),
],
})
If you don’t configure the scheduler provider for your target environment, the worker will not be able to load scheduled tasks.
Worker API
The Worker class provides the following methods:
constructor(app: ApplicationService)
Creates a new worker instance:
import { Worker } from 'adonisjs-scheduler'
import app from '@adonisjs/core/services/app'
const worker = new Worker(app)
async start(tag?: string): Promise<void>
Starts the scheduler worker with an optional tag filter:
// Start with default tag
await worker.start()
// Start with specific tag
await worker.start('reports')
The start method:
- Boots the scheduler and loads all schedules
- Registers cron tasks based on the tag filter
- Begins executing scheduled tasks
async stop(): Promise<void>
Stops all running scheduled tasks:
This gracefully stops all cron tasks but does not wait for currently executing tasks to complete.
async boot(): Promise<void>
Manually boots the worker (normally called automatically by start):
The boot process:
- Loads the scheduler from the container
- Calls the scheduler’s boot method
- Loads command modules
Complete example
Here’s a complete example of a custom server that runs both the HTTP server and scheduler:
import { Worker } from 'adonisjs-scheduler'
import app from '@adonisjs/core/services/app'
import server from '@adonisjs/core/services/server'
import logger from '@adonisjs/core/services/logger'
// Start the HTTP server
const httpServer = await server.start()
logger.info('HTTP server started')
// Start the scheduler worker
const worker = new Worker(app)
await worker.start()
logger.info('Scheduler worker started')
// Handle graceful shutdown
app.terminating(async () => {
logger.info('Shutting down...')
await worker.stop()
logger.info('Scheduler stopped')
await httpServer.close()
logger.info('HTTP server stopped')
})
process.on('SIGTERM', async () => {
await app.terminate()
})
process.on('SIGINT', async () => {
await app.terminate()
})
Worker state management
The worker maintains internal state to prevent duplicate initialization:
import { Worker } from 'adonisjs-scheduler'
import app from '@adonisjs/core/services/app'
const worker = new Worker(app)
// First call boots and starts
await worker.start()
// Subsequent calls to boot do nothing
await worker.boot() // No-op, already booted
Error handling
When using the manual worker, implement proper error handling:
import { Worker } from 'adonisjs-scheduler'
import app from '@adonisjs/core/services/app'
import logger from '@adonisjs/core/services/logger'
const worker = new Worker(app)
try {
await worker.start()
logger.info('Scheduler started successfully')
} catch (error) {
logger.error('Failed to start scheduler:', error)
process.exit(1)
}
app.terminating(async () => {
try {
await worker.stop()
logger.info('Scheduler stopped gracefully')
} catch (error) {
logger.error('Error stopping scheduler:', error)
}
})
The worker logs errors internally using the application’s logger. Individual task failures do not stop the worker.