### start() Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/worker.md Initializes worker processes for each configured queue and begins listening for jobs. This method loads configuration, resolves the logger, gets the job list, determines queues, creates BullWorker instances, and registers event and shutdown handlers. ```APIDOC ## start() ### Description Initializes worker processes for each configured queue and begins listening for jobs. This method loads configuration, resolves the logger, gets the job list, determines queues, creates BullWorker instances, and registers event and shutdown handlers. ### Method `async start(): Promise` ### Returns `Promise` ### Throws - Error if Redis connection fails - Error if job class cannot be loaded from `app/jobs/` directory ### Example ```typescript const worker = new Worker(app, { queues: ['default'] }) await worker.start() // Worker is now listening for jobs ``` ``` -------------------------------- ### Manual Worker Example Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/worker.md A complete example demonstrating how to manually initialize, configure, and start a worker in an AdonisJS application. ```APIDOC ## Complete Manual Worker Example ```typescript import { Worker } from 'adonisjs-jobs' import app from '@adonisjs/core/services/app' async function runWorker() { // Initialize the app (normally done by Ace commands) await app.start() // Create worker for multiple queues const worker = new Worker(app, { queues: ['high', 'default', 'low'], concurrency: [10, 5, 2] // Different concurrency per queue }) // Register shutdown handlers process.on('SIGTERM', async () => { console.log('Shutting down worker gracefully...') await worker.stop() process.exit(0) }) // Start processing await worker.start() } runWorker().catch((error) => { console.error('Worker failed:', error) process.exit(1) }) ``` ``` -------------------------------- ### Queue Registry Example Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/provider.md Shows an example of the queue registry, mapping queue names to their initialized BullMQ Queue instances. ```typescript const queues = { 'default': BullmqQueueInstance, 'mail': BullmqQueueInstance, 'reports': BullmqQueueInstance, } ``` -------------------------------- ### Start Listening to Default Queue Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/commands.md Starts listening to the default Redis queue with a single worker process. This is a common setup for development environments. ```bash node ace jobs:listen ``` -------------------------------- ### Dispatch Job Example Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/dispatcher.md Example demonstrating how to dispatch a Job class to the queue with specific options. ```typescript import { Dispatcher } from 'adonisjs-jobs' import app from '@adonisjs/core/services/app' const dispatcher = await app.container.make('jobs.dispatcher') const jobId = await dispatcher.dispatch( SendEmail, // Job class { email: 'user@example.com', subject: 'Welcome' }, { queueName: 'mail', attempts: 3, delay: 5000 } ) ``` -------------------------------- ### ConnectionOptions Example Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/types.md Example of configuring the Redis connection for the jobs system. Uses environment variables for sensitive information like the password. ```typescript const jobsConfig = defineConfig({ connection: { host: 'localhost', port: 6379, password: env.get('REDIS_PASSWORD') } }) ``` -------------------------------- ### QueueOptions Example Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/types.md Example of setting queue-specific options, such as default job attempts and backoff strategy, within the jobs configuration. ```typescript const jobsConfig = defineConfig({ queueOptions: { defaultJobOptions: { attempts: 3, backoff: { type: 'exponential', delay: 5000 } } } }) ``` -------------------------------- ### Dispatch Closure Example Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/dispatcher.md Example demonstrating how to dispatch a closure function to the queue. ```typescript const dispatcher = await app.container.make('jobs.dispatcher') const jobId = await dispatcher.dispatch( async () => { const { default: User } = await import('#models/user') const count = await User.query().count('*') console.log(`Total users: ${count}`) }, {}, { queueName: 'default' } ) ``` -------------------------------- ### Full defineConfig Example Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/types.md A comprehensive example demonstrating how to configure AdonisJS Jobs with Redis connection details, queue names, default job options, and custom serialization settings. ```typescript import { defineConfig } from 'adonisjs-jobs' const jobsConfig = defineConfig({ connection: { host: 'localhost', port: 6379 }, queue: 'default', queues: ['default', 'mail', 'reports'], options: { attempts: 3, backoff: { type: 'exponential', delay: 5000 }, removeOnComplete: true }, enableSerializedJob: true, serialization: { reducers: { BigInt: (value) => value.toString() }, revivers: { BigInt: (value) => BigInt(value) } } }) export default jobsConfig ``` -------------------------------- ### Install adonisjs-jobs Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/README.md Install the package using pnpm. ```bash pnpm install adonisjs-jobs ``` -------------------------------- ### Start the default jobs listener Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/README.md Start the job listener for the default queue specified in the environment variables. ```sh node ace jobs:listen # default queue from env `REDIS_QUEUE` ``` -------------------------------- ### Start jobs listener with concurrency Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/README.md Start the job listener with a specified concurrency level. ```sh node ace jobs:listen --queue=high --concurrency=3 ``` -------------------------------- ### WorkerOptions Example Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/types.md Example of initializing a Worker with specific queues and concurrency settings. Concurrency can be a single value or an array per queue. ```typescript const worker = new Worker(app, { queues: ['high', 'default', 'low'], concurrency: [10, 5, 2] }) ``` -------------------------------- ### Start the Job Listener Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/commands.md Run the `jobs:listen` command to start the worker process. Use options to specify the queue and concurrency level. ```bash node ace jobs:listen --queue=default --concurrency=5 ``` -------------------------------- ### Start jobs listener for specific queues Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/README.md Start the job listener for specific queues, including multiple queues. ```sh node ace jobs:listen --queue=high node ace jobs:listen --queue=high --queue=medium node ace jobs:listen --queue=high,medium,low ``` -------------------------------- ### Complete Manual Worker Example Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/worker.md Provides a comprehensive example of setting up and running an AdonisJS Jobs worker manually. It includes initializing the app, configuring multiple queues with different concurrency levels, and registering shutdown handlers for graceful termination. ```typescript import { Worker } from 'adonisjs-jobs' import app from '@adonisjs/core/services/app' async function runWorker() { // Initialize the app (normally done by Ace commands) await app.start() // Create worker for multiple queues const worker = new Worker(app, { queues: ['high', 'default', 'low'], concurrency: [10, 5, 2] // Different concurrency per queue }) // Register shutdown handlers process.on('SIGTERM', async () => { console.log('Shutting down worker gracefully...') await worker.stop() process.exit(0) }) // Start processing await worker.start() } runWorker().catch((error) => { console.error('Worker failed:', error) process.exit(1) }) ``` -------------------------------- ### Example WorkerOptions Configuration Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/types.md Illustrates how to configure worker options for job processing, specifying removal strategies for completed and failed jobs. ```typescript const jobsConfig = defineConfig({ workerOptions: { removeOnComplete: { age: 3600 }, removeOnFail: false } }) ``` -------------------------------- ### Example Reducer for DateTime Serialization Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/types.md Example of a reducer function to serialize Luxon DateTime to an ISO string. This can be configured in the serialization settings. ```typescript // Serialize Luxon DateTime to ISO string const reducer = (value: DateTime) => value.toISO() // In config serialization: { reducers: { DateTime: (value) => value.toISO() } } ``` -------------------------------- ### Example Reviver for DateTime Deserialization Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/types.md Example of a reviver function to reconstruct Luxon DateTime from an ISO string. This can be configured in the serialization settings. ```typescript // Revive ISO string to Luxon DateTime const reviver = (value: string) => DateTime.fromISO(value) // In config serialization: { revivers: { DateTime: (value: string) => DateTime.fromISO(value) } } ``` -------------------------------- ### Admin Queue Routes Setup Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/examples.md Sets up routes for queue management, including stats, retry, and remove failed job endpoints. Requires authentication and admin middleware. ```typescript // start/routes.ts router .group(() => { router.get('/stats', 'admin/queue_controller.stats') router.post('/retry-failed', 'admin/queue_controller.retryFailed') router.delete('/remove-failed', 'admin/queue_controller.removeFailed') }) .prefix('/admin/queue') .use(middleware.auth(), middleware.admin()) ``` -------------------------------- ### Example Job Registry Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/provider.md Illustrates the structure of the job registry, mapping job names to their class constructors. Includes the built-in ClosureJob. ```typescript const jobs = { SendEmail: SendEmailClass, ProcessReport: ProcessReportClass, ExportUsers: ExportUsersClass, ClosureJob: ClosureJobClass, // Built-in } ``` -------------------------------- ### Configure adonisjs-jobs Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/README.md Configure the package after installation. ```bash node ace configure adonisjs-jobs ``` -------------------------------- ### Manual Provider Initialization Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/provider.md Manually initialize the JobsProvider and boot it. This is rarely needed but useful for custom setups. After booting, jobs, queues, and the dispatcher become available. ```typescript import JobsProvider from 'adonisjs-jobs/jobs_provider' import app from '@adonisjs/core/services/app' const provider = new JobsProvider(app) await provider.boot() // Now jobs, queues, dispatcher are available const jobs = await app.container.make('jobs.list') const dispatcher = await app.container.make('jobs.dispatcher') ``` -------------------------------- ### Configure Custom Class Serialization Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/configuration.md Example of configuring serialization for a custom class like Money using reducers and revivers. ```typescript import { Money } from 'dinero.js' const jobsConfig = defineConfig({ serialization: { reducers: { Money: (value) => { if (!(value instanceof Money)) return null return { amount: value.getAmount(), currency: value.getCurrency() } } }, revivers: { Money: ({ amount, currency }) => Money({ amount, currency }) } } }) ``` -------------------------------- ### Mounting the Jobs Dashboard Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/types.md Examples of using the router's `jobs` method to mount the dashboard at the default path, a custom path, or with middleware. ```typescript router.jobs() // /jobs router.jobs('/admin/jobs') // /admin/jobs router.jobs().use(middleware.auth()) // With auth ``` -------------------------------- ### Worker.start() Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/worker.md Starts the background job processor, making it listen to Redis queues and execute queued jobs. ```APIDOC ## start() ### Description Starts the worker to listen to Redis queues and execute jobs. ### Method async start(): Promise ``` -------------------------------- ### Listen to Multiple Queues Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/commands.md Starts the worker to process jobs from multiple specified queues. Jobs from any of these queues will be processed. ```bash node ace jobs:listen --queue=high --queue=default --queue=low ``` -------------------------------- ### Start Worker Processes Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/worker.md Initializes worker processes for specified queues and begins listening for jobs. Ensure the Worker is instantiated with the application instance and desired queues. ```typescript const worker = new Worker(app, { queues: ['default'] }) await worker.start() // Worker is now listening for jobs ``` -------------------------------- ### Mounting Dashboard Routes Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/provider.md Illustrates how to use the router extension to mount the job queue dashboard UI at a specified URL pattern. Includes examples with default and custom paths, and applying middleware. ```typescript // Default - mounts at /jobs router.jobs() // Custom path router.jobs('/admin/jobs') router.jobs('/queue-management') // With middleware router.jobs().use(middleware.auth()) router.jobs().use([middleware.auth(), middleware.can('manage-jobs')]) ``` -------------------------------- ### Custom Redis Host and Queue Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/commands.md Starts the worker with custom Redis host and port, and specifies a particular queue to process. Useful for non-default Redis configurations. ```bash REDIS_HOST=redis.production.com REDIS_PORT=6380 node ace jobs:listen --queue=critical ``` -------------------------------- ### Complete Job with All Lifecycle Hooks Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/examples.md This example demonstrates a complete job implementation including `handle`, `failed`, and `completed` lifecycle hooks. Use this pattern to manage complex job logic, error handling, and post-completion notifications. ```typescript // app/jobs/generate_report.ts import { Job } from 'adonisjs-jobs' interface GenerateReportPayload { reportId: number format: 'pdf' | 'csv' } export default class GenerateReport extends Job { async handle(payload: GenerateReportPayload) { const report = await Report.findOrFail(payload.reportId) this.logger.info(`Generating ${payload.format} report ${report.id}`) report.status = 'generating' report.startedAt = new Date() await report.save() // Generate report (simplified) const data = await this.generateReportData(report) const filePath = await this.formatReport(data, payload.format) report.filePath = filePath return { success: true, filePath } } async failed(error: Error) { this.logger.error(`Report generation failed: ${error.message}`) const report = await Report.find(this.job.data.reportId) if (report) { report.status = 'failed' report.error = error.message await report.save() } // Alert admin await SendEmail.dispatch({ to: 'admin@example.com', subject: `Report Generation Failed`, template: 'admin_alert', data: { reportId: this.job.data.reportId, error: error.message } }, { queueName: 'mail' }) } async completed(payload: GenerateReportPayload, result: any) { this.logger.info(`Report generated successfully`) const report = await Report.findOrFail(payload.reportId) report.status = 'completed' report.completedAt = new Date() await report.save() // Notify user await SendEmail.dispatch({ to: report.user.email, subject: 'Your Report is Ready', template: 'report_ready', data: { reportName: report.name, downloadUrl: `/reports/${report.id}/download` } }, { queueName: 'mail' }) } private async generateReportData(report: Report) { // ... implementation } private async formatReport(data: any, format: string) { // ... implementation } } ``` -------------------------------- ### Using Environment Variable for Queue Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/commands.md Starts the worker listening to a queue specified by the REDIS_QUEUE environment variable. This allows dynamic queue configuration without modifying the command. ```bash REDIS_QUEUE=mail node ace jobs:listen ``` -------------------------------- ### Accessing Queues Binding Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/provider.md Demonstrates how to access the 'jobs.queues' binding from the container to get the map of initialized BullMQ queues. ```typescript const queues = await app.container.make('jobs.queues') // Usage const defaultQueue = queues['default'] ``` -------------------------------- ### Usage of Priority-Based Queue Routing Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/examples.md Examples of using the NotificationService to send notifications with different priorities, demonstrating routing to 'critical' and 'low' queues. ```typescript // Urgent notification await NotificationService.sendNotification( user.id, 'Your account is at risk', 'critical' ) // Marketing email await NotificationService.sendNotification( user.id, 'Check out our new features!', 'low' ) ``` -------------------------------- ### Initialize and start job worker manually Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/README.md Manually initialize and control the job worker using the Worker class. ```ts import { Worker } from 'adonisjs-jobs' import app from '@adonisjs/core/services/app' const worker = new Worker(app, { queues: ['default', 'mail'], concurrency: 1, }) app.terminating(async () => { await worker.stop() }) await worker.start() ``` -------------------------------- ### Kubernetes Grace Period Example Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/commands.md Illustrates the Kubernetes configuration for setting a graceful shutdown period for the job worker pod. This allows running jobs to complete before the pod is terminated. ```yaml terminationGracePeriodSeconds: 1800 ``` -------------------------------- ### Implement Job Handle Method Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/commands.md Implement the core logic of your job within the `handle` method. This example demonstrates sending an email using AdonisJS Mail service and fetching user data. ```typescript async handle(payload: SendEmailPayload) { const { default: mail } = await import('@adonisjs/mail/services/main') const { default: User } = await import('#models/user') const user = await User.findOrFail(payload.userId) await mail.send((message) => { message .to(payload.email) .from('noreply@example.com') .htmlView(`emails/${payload.template}`, { user }) }) } ``` -------------------------------- ### Listen to Comma-Separated Queues Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/commands.md Starts the worker to process jobs from multiple queues specified as a comma-separated string. The command parses this into an array of queues. ```bash node ace jobs:listen --queue=high,default,low ``` -------------------------------- ### Dispatch Job to Send Daily Digest Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/examples.md This example dispatches a job to send a daily digest to users. It queries users who have digests enabled and dispatches a separate `SendDigest` job for each, specifying a 'mail' queue. ```typescript // Send daily digest await dispatch(async () => { const { default: User } = await import('#models/user') const users = await User.query().where('digest_enabled', true) for (const user of users) { await SendDigest.dispatch({ userId: user.id, digest: await this.buildDigest(user) }, { queueName: 'mail' }) } }) ``` -------------------------------- ### Troubleshooting Redis Connection Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/commands.md Provides a command to test Redis connection details by explicitly setting the host and port when starting the jobs:listen command. This helps diagnose connection issues. ```bash # Check Redis connection details REDIS_HOST=your-host REDIS_PORT=6379 node ace jobs:listen ``` -------------------------------- ### Accessing Worker Count Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/worker.md Demonstrates how to access the number of BullWorker instances after starting the worker. This is useful for verifying worker initialization. ```typescript const worker = new Worker(app, { queues: ['default', 'mail'] }) await worker.start() console.log(worker.workers.length) // 2 ``` -------------------------------- ### Check Job File Location and Naming Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/provider.md Verify that job files are located in the `app/jobs/` directory and do not have a hidden name prefix (e.g., starting with an underscore). Ensure the file extension is valid (e.g., `.ts`, `.js`). ```bash # Check file location ls -la app/jobs/ # Ensure no leading underscore # ✅ app/jobs/send_email.ts # ❌ app/jobs/_send_email.ts # Check file extension # ✅ .ts, .js, .cjs, .mjs # ❌ .d.ts (excluded) ``` -------------------------------- ### Listen to a Specific Queue Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/commands.md Starts the worker to process jobs from a specific Redis queue, such as 'mail'. Useful for isolating different types of jobs. ```bash node ace jobs:listen --queue=mail ``` -------------------------------- ### Dispatch Job in Service Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/services.md Illustrates how to dispatch a job from a service class in AdonisJS. This example queues a report processing job with specific options. ```typescript import { dispatch } from 'adonisjs-jobs/services/main' import ProcessReport from '#jobs/process_report' export default class ReportService { async generateReport(reportId: number) { const report = await Report.findOrFail(reportId) report.status = 'processing' await report.save() // Queue processing job await dispatch(ProcessReport, { reportId: report.id, format: 'pdf' }, { queueName: 'reporting', attempts: 3 }) } } ``` -------------------------------- ### Dispatch Inline Async Function Job Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/examples.md This example demonstrates dispatching an inline async function as a job. It updates the `lastSeenAt` timestamp for users who haven't been active recently. ```typescript import { dispatch } from 'adonisjs-jobs/services/main' // Update user last seen timestamp await dispatch(async () => { const { default: User } = await import('#models/user') const yesterday = DateTime.now().minus({ days: 1 }) await User.query() .where('lastSeenAt', '<', yesterday) .update({ lastSeenAt: DateTime.now() }) }) ``` -------------------------------- ### JobsProvider boot() Method Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/provider.md Called during the application boot process to initialize the jobs system. This method handles loading job files, registering jobs, initializing queues, registering container bindings, and mounting the job queue dashboard. ```APIDOC ## boot() ### Description Called during application boot to initialize the jobs system. ### Signature ```typescript async boot(): Promise ``` ### Returns `Promise` ### Execution Steps 1. **Load Job Files** - Discovers and imports all job classes from `app/jobs/` 2. **Register Jobs** - Stores loaded jobs in jobs registry (map by class name) 3. **Initialize Queues** - Creates BullMQ Queue instances for each configured queue 4. **Register Bindings** - Adds containers bindings for jobs, queues, dispatcher 5. **Mount Dashboard** - Registers `/jobs` route with QueueDash UI 6. **Register Shutdown** - Hooks into app termination for cleanup ``` -------------------------------- ### Queue Initialization Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/provider.md Demonstrates how to initialize BullMQ queue instances based on configuration. It applies queue-specific options, global connection settings, and default job options. ```typescript const queues = config.queues.reduce((acc, name) => { const queue = new BullmqQueue(name, { ...(config.queueOptions || {}), connection: config.connection, defaultJobOptions: config.options, }) acc[name] = queue return acc }, {} as Record) ``` -------------------------------- ### JobsProvider boot() Method Signature Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/provider.md The boot method of the JobsProvider. This asynchronous method is called during the application's boot process to initialize the jobs system, including loading jobs, setting up queues, and registering bindings. ```typescript async boot(): Promise ``` -------------------------------- ### Multi-Queue Configuration and Dispatch Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/configuration.md Sets up multiple queues and demonstrates dispatching jobs to specific queues by name. ```typescript const jobsConfig = defineConfig({ connection: { host: env.get('REDIS_HOST', 'localhost'), port: env.get('REDIS_PORT', 6379), }, queue: 'default', queues: ['critical', 'high', 'default', 'low', 'imports'], options: { attempts: 3, backoff: { type: 'exponential', delay: 3000 }, }, }) // Dispatch to specific queues await CriticalJob.dispatch(payload, { queueName: 'critical' }) await ImportJob.dispatch(payload, { queueName: 'imports' }) ``` -------------------------------- ### Dispatch Closure Job Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/configuration.md Example of dispatching an inline async function after enabling `enableSerializedJob`. ```typescript import { dispatch } from 'adonisjs-jobs/services/main' // Now closure jobs work await dispatch(async () => { console.log('This is a closure job') }) ``` -------------------------------- ### Troubleshooting Queue Not Found Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/commands.md Shows how to ensure a queue name is valid by explicitly providing it to the jobs:listen command. This helps when encountering 'Queue not found' errors. ```bash # Ensure queue exists in config/jobs.ts node ace jobs:listen --queue=valid-queue-name ``` -------------------------------- ### Get REDIS_PASSWORD Environment Variable Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/configuration.md Retrieves the Redis password from environment variables. This is optional. ```typescript password: env.get('REDIS_PASSWORD') ``` -------------------------------- ### Get REDIS_PORT Environment Variable Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/configuration.md Retrieves the Redis port from environment variables, defaulting to 6379. ```typescript port: env.get('REDIS_PORT', 6379) ``` -------------------------------- ### Get REDIS_HOST Environment Variable Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/configuration.md Retrieves the Redis host from environment variables, defaulting to 'localhost'. ```typescript host: env.get('REDIS_HOST', 'localhost') ``` -------------------------------- ### Get REDIS_QUEUE Environment Variable Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/configuration.md Retrieves the default Redis queue name from environment variables, defaulting to 'default'. ```typescript queue: env.get('REDIS_QUEUE', 'default') ``` -------------------------------- ### Accessing Dispatcher Binding Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/provider.md Shows how to retrieve the 'jobs.dispatcher' binding from the container to get the Dispatcher service instance for dispatching jobs. ```typescript const dispatcher = await app.container.make('jobs.dispatcher') // Usage const jobId = await dispatcher.dispatch(JobClass, payload, options) ``` -------------------------------- ### Troubleshooting No Jobs Processed Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/commands.md Offers steps to troubleshoot why no jobs are being processed, including checking job dispatch and monitoring Redis queues directly using redis-cli. ```bash # Check if jobs are being dispatched # Monitor Redis with redis-cli redis-cli > LRANGE queue-name 0 -1 ``` -------------------------------- ### Set Concurrency for All Queues Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/commands.md Sets the number of jobs to process in parallel across all queues. This example processes 5 jobs concurrently. ```bash node ace jobs:listen --concurrency=5 ``` -------------------------------- ### Configure import aliases in package.json Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/README.md Set up import aliases in package.json for easier module resolution. ```json { "imports": { "#jobs/*": "./app/jobs/*.js" } } ``` -------------------------------- ### Initialize Dispatcher on App Boot Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/services.md Ensures the dispatcher is ready before any jobs are dispatched. This initialization is automatic. ```typescript await app.booted(async () => { dispatcher = await app.container.make('jobs.dispatcher') }) ``` -------------------------------- ### Development Configuration Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/configuration.md Sets up jobs for development with a single attempt and disabled removal on complete/fail for debugging. ```typescript const jobsConfig = defineConfig({ connection: { host: 'localhost', port: 6379, }, queue: 'default', queues: ['default'], options: { attempts: 1, // Single attempt for quick feedback removeOnComplete: false, // Keep jobs for debugging removeOnFail: false, }, enableSerializedJob: true, }) ``` -------------------------------- ### Create a New Job Class Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/commands.md Use the `jobs:make` command to generate a new job class file. The argument specifies the name of the job. ```bash node ace jobs:make SendNotification ``` -------------------------------- ### Access Dispatcher from Container Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/dispatcher.md Retrieves the registered Dispatcher instance from the IoC container. This is the standard way to get an instance of the dispatcher to dispatch jobs. ```typescript const dispatcher = await app.container.make('jobs.dispatcher') ``` -------------------------------- ### Multiple Workers in Parallel (Separate Terminals) Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/commands.md Demonstrates running multiple instances of the jobs:listen command in parallel, each dedicated to a specific queue and concurrency level. This is useful for scaling job processing. ```bash # Terminal 1 - High priority jobs node ace jobs:listen --queue=high --concurrency=5 # Terminal 2 - Low priority jobs node ace jobs:listen --queue=low --concurrency=2 # Terminal 3 - Default jobs node ace jobs:listen --queue=default --concurrency=3 ``` -------------------------------- ### JobHandle Type Usage Example Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/types.md Demonstrates how JobHandle infers the payload type for a job's handle method and how this type is enforced when dispatching a job. ```typescript class SendEmail extends Job { async handle(payload: { email: string; subject: string }) { // JobHandle = { email: string; subject: string } } } // This ensures dispatch() requires this exact payload type await SendEmail.dispatch({ email: 'user@example.com', subject: 'Welcome' }) ``` -------------------------------- ### JobsOptions Type (from BullMQ) Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/types.md Complete options for job creation, passed to dispatch methods. Includes settings like attempts, delay, backoff, and repeat patterns. ```typescript type JobsOptions = { attempts?: number delay?: number backoff?: { type: 'exponential' | 'fixed' delay: number } removeOnComplete?: boolean | number | { age?: number count?: number } removeOnFail?: boolean | number | { age?: number count?: number } priority?: number repeat?: { pattern?: string // cron expression every?: number } timeout?: number stackTrace?: boolean // ... additional options from BullMQ } ``` -------------------------------- ### Dispatching Job with Exponential Backoff Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/examples.md Dispatch the SyncExternalData job with a configured retry strategy, including 5 attempts and exponential backoff starting at 5 seconds. ```typescript await SyncExternalData.dispatch( { resourceId: 123 }, { attempts: 5, backoff: { type: 'exponential', delay: 5000 // 5s, 10s, 20s, 40s, 80s } } ) ``` -------------------------------- ### Create a new job Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/README.md Generate a new job class using the Ace CLI. ```sh node ace jobs:make SendEmail ``` -------------------------------- ### Dispatch Job with Delayed Execution Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/services.md Schedule jobs to run after a specified delay in milliseconds. Examples include sending a reminder email in 1 hour or scheduling a weekly digest. ```typescript // Send reminder email in 1 hour await dispatch(SendReminder, { userId: 123 }, { delay: 3600000 } // milliseconds ) // Send weekly digest on Monday at 9am const daysUntilMonday = (8 - new Date().getDay()) % 7 || 7 const msUntilMonday = daysUntilMonday * 24 * 60 * 60 * 1000 await dispatch(WeeklyDigest, payload, { delay: msUntilMonday }) ``` -------------------------------- ### Generate a New Job Class Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/commands.md Use the `jobs:make` command to create a new job class file. The command automatically converts the input name to PascalCase for the class name and snake_case for the filename. ```bash node ace jobs:make [options] ``` ```bash node ace jobs:make SendEmail ``` ```bash node ace jobs:make ProcessReport ``` ```bash node ace jobs:make ExportUsers ``` ```bash node ace jobs:make SendEmail node ace jobs:make ProcessReport node ace jobs:make GenerateInvoice ``` ```bash node ace jobs:make SendWelcomeEmail node ace jobs:make ProcessMonthlyReport ``` -------------------------------- ### Dispatch Job in Route Handler Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/services.md Demonstrates queuing a job from an AdonisJS route handler to perform tasks asynchronously without blocking the HTTP response. This example queues an email job. ```typescript import { dispatch } from 'adonisjs-jobs/services/main' import SendEmail from '#jobs/send_email' export default class UsersController { async store({ request, response }: HttpContext) { const payload = request.validate(CreateUserValidator) const user = await User.create(payload) // Queue welcome email without blocking response await dispatch(SendEmail, { userId: user.id, email: user.email, subject: 'Welcome to Our App' }, { queueName: 'mail' }) return response.created(user) } } ``` -------------------------------- ### QueueDash Initial State Configuration Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/provider.md Configure the initial state for the QueueDash UI by setting the API endpoint and base URL. This is typically done in your application's main HTML file. ```javascript window.__INITIAL_STATE__ = { apiUrl: '/jobs/trpc', // API endpoint basename: '/jobs', // Base URL for navigation } ``` -------------------------------- ### Recommended Dispatch Usage Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/dispatcher.md Recommended usage via the exported dispatch function from 'adonisjs-jobs/services/main'. This function waits for app boot before dispatching. ```typescript import { dispatch } from 'adonisjs-jobs/services/main' await dispatch(JobClass, payload, options) ``` -------------------------------- ### Resolving Job Container Bindings Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/types.md Demonstrates how to resolve the 'jobs.list', 'jobs.queues', and 'jobs.dispatcher' bindings from the IoC container. ```typescript const jobs = await app.container.make('jobs.list') const queues = await app.container.make('jobs.queues') const dispatcher = await app.container.make('jobs.dispatcher') ``` -------------------------------- ### Listen Using Short Alias for Queue Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/commands.md Uses the short alias '-q' to specify a single queue for the worker to process. This is a shorthand for the --queue option. ```bash node ace jobs:listen -q mail ``` -------------------------------- ### Job vs Closure Detection Logic Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/dispatcher.md The dispatcher determines job type using regex on the function's string representation. Functions starting with 'class ' are treated as job classes; others are closures. ```typescript const isClosure = !( typeof jobOrClosure === 'function' && /^class\s/.test(jobOrClosure.toString()) ) ``` -------------------------------- ### Debug Endpoint: Check Configuration Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/provider.md Expose a route to view the current jobs configuration. This includes settings like 'queues' and 'enableSerializedJob'. ```typescript import router from '@adonisjs/core/services/router' import app from '@adonisjs/core/services/app' router.get('/debug/config', async ({ response }) => { const config = app.config.get('jobs') return response.json({ queues: config.queues, enableSerializedJob: config.enableSerializedJob, }) }) ``` -------------------------------- ### ConnectionOptions Type (from BullMQ) Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/types.md Redis connection configuration used in defineConfig. Supports standard ioredis options for establishing a connection. ```typescript type ConnectionOptions = { host?: string port?: number password?: string db?: number username?: string tls?: boolean family?: 4 | 6 lazyConnect?: boolean keepAlive?: number maxRetriesPerRequest?: number | null enableReadyCheck?: boolean enableOfflineQueue?: boolean // ... additional options from ioredis } ``` -------------------------------- ### Dispatch a job with default options Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/README.md Dispatch a job with default BullMQ options. ```ts import SendEmail from 'path/to/jobs/send_email.js' await SendEmail.dispatch({ ... }) ``` -------------------------------- ### Kubernetes Deployment for Graceful Shutdown Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/worker.md Configure Kubernetes to allow sufficient time for long-running jobs to complete before container termination. Adjust `terminationGracePeriodSeconds` as needed. ```yaml spec: containers: - name: jobs-worker image: myapp:latest command: ['node'] args: ['ace', 'jobs:listen', '--queue=default'] # Graceful termination period (default 30s usually not enough) terminationGracePeriodSeconds: 1800 # 30 minutes ``` -------------------------------- ### Accessing BullMQ Job Instance in AdonisJS Job Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/job.md Access the underlying BullMQ Job instance within an AdonisJS Job to get job details like ID and attempt count. This property is read-only and set by the worker during processing. ```typescript export default class SendEmail extends Job { async handle(payload: any) { this.logger.info(`Processing job ${this.job.id}`) this.logger.info(`Attempt ${this.job.attemptsMade} of ${this.job.opts.attempts}`) } } ``` -------------------------------- ### Job Class Instance Methods Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/INDEX.md Instance methods available on a Job class instance for handling job lifecycle events. ```APIDOC ## Job.handle() ### Description Handles the execution of the job with the given payload. ### Method N/A (Instance method) ### Signature `handle(payload): Promise | any` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response - `Promise | any`: The result of the job execution. ### Response Example None ``` ```APIDOC ## Job.failed() ### Description Callback function executed when a job fails. ### Method N/A (Instance method) ### Signature `failed(error): Promise | void` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response - `Promise | void`: Indicates completion of the failure handling. ### Response Example None ``` ```APIDOC ## Job.completed() ### Description Callback function executed when a job completes successfully. ### Method N/A (Instance method) ### Signature `completed(payload, result): Promise | void` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response - `Promise | void`: Indicates completion of the success handling. ### Response Example None ``` -------------------------------- ### Minimize Job Directory for Boot Time Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/provider.md For applications with a large number of job files, lazy loading can slow down application boot time. Minimize this by removing unused job files from the directory. ```typescript // Large job directory can slow boot time // Minimize by removing unused job files ``` -------------------------------- ### Production Configuration Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/configuration.md Configures jobs for production with environment variable-based settings, retries, and specific backoff strategies. ```typescript const jobsConfig = defineConfig({ connection: { host: env.get('REDIS_HOST'), port: env.get('REDIS_PORT', 6379), password: env.get('REDIS_PASSWORD'), tls: true, db: 1, // Use separate DB from cache }, queue: env.get('REDIS_QUEUE', 'default'), queues: ['critical', 'high', 'default', 'low'], options: { attempts: 5, // Retry failed jobs backoff: { type: 'exponential', delay: 5000, }, removeOnComplete: { age: 3600 }, // Keep for 1 hour removeOnFail: { age: 86400 }, // Keep for 1 day }, enableSerializedJob: false, // Security - no inline functions }) ``` -------------------------------- ### Restart Application to Reload Configuration Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/configuration.md Configuration is loaded at app boot time and cached. To apply runtime configuration changes, the application must be restarted. Use `npm run dev` for automatic restarts during development. ```typescript // Restart required - config is not reloaded dynamically await app.restart() ``` -------------------------------- ### Redis Connection for Local Development Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/configuration.md Configure the Redis connection for local development using default host and port. ```typescript connection: { host: 'localhost', port: 6379, } ``` -------------------------------- ### Redis Connection with TLS/SSL for Production Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/configuration.md Configure a secure Redis connection using TLS/SSL, suitable for production environments. ```typescript connection: { host: 'redis.example.com', port: 6380, password: env.get('REDIS_PASSWORD'), tls: true, } ``` -------------------------------- ### Default Configuration Template Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/configuration.md This template shows the default structure for the `config/jobs.ts` file. It includes settings for Redis connection, queue name, supported queues, and job processing options like attempts, backoff strategy, and removal policies. ```typescript import env from '#start/env' import { defineConfig } from 'adonisjs-jobs' const jobsConfig = defineConfig({ connection: { host: env.get('REDIS_HOST', 'localhost'), port: env.get('REDIS_PORT', 6379), password: env.get('REDIS_PASSWORD'), }, queue: env.get('REDIS_QUEUE', 'default'), queues: ['default'], options: { /** * The total number of attempts to try the job until it completes. */ attempts: 0, /** * Backoff setting for automatic retries if the job fails */ backoff: { type: 'exponential', delay: 5000, }, /** * If true, removes the job when it successfully completes * When given a number, it specifies the maximum amount of * jobs to keep, or you can provide an object specifying max * age and/or count to keep. It overrides whatever setting is used in the worker. * Default behavior is to keep the job in the completed set. */ removeOnComplete: 1000, /** * If true, removes the job when it fails after all attempts. * When given a number, it specifies the maximum amount of * jobs to keep, or you can provide an object specifying max * age and/or count to keep. It overrides whatever setting is used in the worker. * Default behavior is to keep the job in the failed set. */ removeOnFail: 1000, }, }) export default jobsConfig ``` -------------------------------- ### Configure BullMQ Queue Settings Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/configuration.md Set BullMQ queue-level configurations like stalled job checking intervals and maximum stalled counts. ```typescript queueOptions: { settings: { stalledInterval: 15000, maxStalledCount: 2 } } ``` -------------------------------- ### Schedule Daily and Hourly Jobs with node-cron Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/examples.md Schedule various jobs like daily cleanup, daily digests, and hourly updates using the node-cron library. Ensure the necessary job classes are imported and dispatched correctly. ```typescript // start/jobs_scheduler.ts import cron from 'node-cron' import { dispatch } from 'adonisjs-jobs/services/main' import CleanupExpiredSessions from '#jobs/cleanup_expired_sessions' import SendDailyDigest from '#jobs/send_daily_digest' export default function scheduleJobs() { // Every day at 2 AM cron.schedule('0 2 * * *', async () => { await dispatch(CleanupExpiredSessions, {}) }) // Every day at 9 AM cron.schedule('0 9 * * *', async () => { const users = await User.query().where('digest_enabled', true) for (const user of users) { await dispatch(SendDailyDigest, { userId: user.id }) } }) // Every hour cron.schedule('0 * * * *', async () => { await dispatch(UpdateCurrencyRates, {}) }) } ``` -------------------------------- ### Configure import aliases in tsconfig.json Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/README.md Set up import aliases in tsconfig.json for TypeScript projects. ```json { "compilerOptions": { "paths": { "#jobs/*": ["./app/jobs/*.js"] } } } ``` -------------------------------- ### handle() - Abstract Method Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/job.md The abstract `handle` method is the core of any Job subclass. It must be implemented to define the actual processing logic for a job. It receives a payload and can return a value or a promise. ```APIDOC ## handle() ### Description Abstract method that processes the job. Must be implemented by all Job subclasses. ### Signature ```typescript abstract handle(payload: any): Promise | any ``` ### Parameters #### Path Parameters - **payload** (any) - Required - Data passed during job dispatch, typed by implementation. ### Returns `Promise | any` - Any value returned by the job (can be used in `completed()` hook) ### Throws - Any error thrown is caught by worker and triggers retry logic - After max attempts exhausted, calls `failed()` hook ### Example ```typescript export default class SendEmail extends Job { async handle(payload: { email: string; subject: string }) { const { default: mail } = await import('@adonisjs/mail/services/main') await mail.send((message) => { message .to(payload.email) .from('no-reply@example.com') .subject(payload.subject) .htmlView('emails/welcome') }) return { sent: true } } } ``` ``` -------------------------------- ### Dispatch Simple Job Source: https://github.com/kabbouchi/adonisjs-jobs/blob/main/_autodocs/api-reference/services.md The most common pattern for queuing jobs. Requires importing the `dispatch` function and the job class. ```typescript import { dispatch } from 'adonisjs-jobs/services/main' import SendEmail from '#jobs/send_email' await dispatch(SendEmail, { email: 'user@example.com' }) ```