{"id":27131140,"url":"https://github.com/shiny/adonis-resque","last_synced_at":"2026-02-22T08:37:53.433Z","repository":{"id":230414479,"uuid":"779215588","full_name":"shiny/adonis-resque","owner":"shiny","description":"Resque Queue for AdonisJS v6","archived":false,"fork":false,"pushed_at":"2025-07-16T07:09:56.000Z","size":130,"stargazers_count":31,"open_issues_count":3,"forks_count":5,"subscribers_count":1,"default_branch":"v2","last_synced_at":"2025-10-24T03:47:15.968Z","etag":null,"topics":["adonisjs","queue","resque"],"latest_commit_sha":null,"homepage":"https://packages.adonisjs.com/packages/resque","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/shiny.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null},"funding":{"github":["tealight-uk","shiny"],"patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":null,"thanks_dev":null,"custom":null}},"created_at":"2024-03-29T09:57:37.000Z","updated_at":"2025-07-16T07:10:00.000Z","dependencies_parsed_at":"2024-03-31T20:29:04.303Z","dependency_job_id":"3ec298e9-c995-4181-830f-6e319a9d4b77","html_url":"https://github.com/shiny/adonis-resque","commit_stats":null,"previous_names":["shiny/adonis-resque"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/shiny/adonis-resque","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shiny%2Fadonis-resque","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shiny%2Fadonis-resque/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shiny%2Fadonis-resque/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shiny%2Fadonis-resque/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/shiny","download_url":"https://codeload.github.com/shiny/adonis-resque/tar.gz/refs/heads/v2","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/shiny%2Fadonis-resque/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29707030,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-22T05:59:28.568Z","status":"ssl_error","status_checked_at":"2026-02-22T05:58:46.208Z","response_time":110,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["adonisjs","queue","resque"],"created_at":"2025-04-07T20:38:38.733Z","updated_at":"2026-02-22T08:37:53.404Z","avatar_url":"https://github.com/shiny.png","language":"TypeScript","funding_links":["https://github.com/sponsors/tealight-uk","https://github.com/sponsors/shiny"],"categories":[],"sub_categories":[],"readme":"\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://i.imgur.com/SWHLZNO.png\" /\u003e\n  \u003ch3\u003eNode Resque Queue for AdonisJS v6\u003c/h3\u003e\n  \u003cp\u003eA third-party wrapper for `node-resque` in AdonisJS v6.\u003c/p\u003e\n  \u003ca href=\"https://www.npmjs.com/package/adonis-resque\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/adonis-resque?logo=nodedotjs\" /\u003e\u003c/a\u003e\n  \u003cimg src=\"https://img.shields.io/badge/Lang-typescript-blue?logo=typescript\" /\u003e\n  \u003cimg src=\"https://img.shields.io/npm/l/adonis-resque?logo=opensourceinitiative\" /\u003e\n\u003c/div\u003e\n\n\u003e [!CAUTION]\n\u003e This package is not compatible with AdonisJS v5.\n\n\u003c!-- TOC --\u003e\n\n- [Introduction](#introduction)\n- [Installation](#installation)\n- [Folders](#folders)\n- [Job Usage](#job-usage)\n  - [Basic](#basic)\n  - [Batch enqueue](#batch-enqueue)\n  - [Delayed enqueue](#delayed-enqueue)\n  - [Repeated Enqueue](#repeated-enqueue)\n- [Handle Failure Jobs](#handle-failure-jobs)\n  - [Job.onFailure](#jobonfailure)\n  - [Failure Event](#failure-event)\n- [Dependency Injection in Job Classes](#dependency-injection-in-job-classes)\n- [Demonstration](#demonstration)\n  - [Send Mail Job](#send-mail-job)\n- [Plugin](#plugin)\n  - [Plugin.jobLock](#pluginjoblock)\n  - [Plugin.queueLock](#pluginqueuelock)\n  - [Plugin.delayQueueLock](#plugindelayqueuelock)\n  - [Plugin.retry](#pluginretry)\n  - [Plugin.noop](#pluginnoop)\n  - [Custom Your Own Plugin](#custom-your-own-plugin)\n- [Configuration](#configuration)\n- [Concepts \\\u0026 Components](#concepts--components)\n  - [Queue](#queue)\n    - [Example: Getting a total count of pending jobs](#example-getting-a-total-count-of-pending-jobs)\n  - [Worker](#worker)\n    - [Multi Worker](#multi-worker)\n  - [Scheduler](#scheduler)\n- [Deployment](#deployment)\n  - [Development](#development)\n  - [Production](#production)\n- [Web UI](#web-ui)\n- [Notice 1: for the graceful exit](#notice-1-for-the-graceful-exit)\n- [Notice 2: Job does not `@inject`able](#notice-2-job-does-not-injectable)\n- [Who's Using](#whos-using)\n- [Contributors](#contributors)\n- [Reference](#reference)\n- [Migration from v1 to v2](#migration-from-v1-to-v2)\n  - [Changes in ver 2](#changes-in-ver-2)\n    - [this.logger Removed](#thislogger-removed)\n    - [Chainable Methods Removed](#chainable-methods-removed)\n    - [Dependency Injection Now Available in Job Files](#dependency-injection-now-available-in-job-files)\n- [License](#license)\n\n\u003c!-- /TOC --\u003e\n\u003c!-- /TOC --\u003e\n\u003c!-- /TOC --\u003e\n\n\u003c!-- /TOC --\u003e\n\n\u003c!-- /TOC --\u003e\n\u003c!-- /TOC --\u003e\n\u003c!-- /TOC --\u003e\n\u003c!-- /TOC --\u003e\n\n\u003c!-- /TOC --\u003e\n\u003c!-- /TOC --\u003e\n\n## Introduction\n`adonis-resque` add the queue ability to adonis base on node-resque. Resque is a background job system backed by Redis.\n\n## Installation\n\n```bash\nnpm i adonis-resque\nnode ace configure adonis-resque\n```\n\u003e [!IMPORTANT]\n\u003e `@adonisjs/redis` is required for resque redis connection.\n\u003e \n## Folders\n\nJobs are placed in folder `app/jobs` by default.\nYou can import job through sub-path.\n```typescript\nimport Example from '#jobs/example'\n```\n\n\u003e [!TIP]\n\u003e Please follow this instruction: [The sub-path imports](https://docs.adonisjs.com/guides/folder-structure#the-sub-path-imports).\n\u003e \n\u003e Both `package.json` and `tsconfig.json` are required to add the job path:\n\u003e - add to `package.json`\n\u003e  ```json\n\u003e  \"#jobs/*\": \"./app/jobs/*.js\"\n\u003e  ```\n\u003e - add to field `compilerOptions.paths` in `tsconfig.json`\n\u003e  ```json\n\u003e  \"#jobs/*\": [\"./app/jobs/*.js\"]\n\u003e  ```\n\n\n## Job Usage\nYou can create a resque job by adonis command: `node ace make:job \u003cYourJobName\u003e`\n\n### Basic\n\nCreate a basic example job: `node ace make:job BasicExample`.\nEvery job has a perform method. It runs in the background, which consumer from the node-resque queue.\n\n```typescript\nimport { BaseJob } from 'adonis-resque'\nimport logger from '@adonisjs/core/services/logger'\nexport default class BasicExample extends BaseJob {\n  async perform(name: string) {\n    logger.info(`Hello ${name}`)\n  }\n}\n```\n\nNow you can enqueue this job. \n```typescript\nimport BasicExample from '#jobs/basic_example'\nawait BasicExample.enqueue('Bob')\n```\n\nConsole would print `Hello Bob`.\n\n\u003e [!WARNING]\n\u003e Make sure your Job ClassName is unique in the queue. and the arguments of it's method `perform` would be serialize to a json string to redis under the hood.\n\n### Batch enqueue\n```typescript\nawait BasicExample.enqueueAll([\n  ['Alice'],\n  ['Bob'],\n  ['Carol'],\n  ['Dave'],\n  ['Eve']\n])\n```\n\n### Delayed enqueue\n```typescript\nconst oneSecondLater = 1000\nawait BasicExample.enqueueIn(oneSecondLater, 'Bob')\n```\nOr enqueue at a specify timestamp\n```typescript\nconst fiveSecondsLater = new Date().getTime() + 5000\nawait BasicExample.enqueueAt(fiveSecondsLater, 'Bob')\n```\n\n### Repeated Enqueue\n\nclass Job has the schedule properties.\n- `interval`, .e.g `5s`, `15m`, `2h` and `1d`. [package ms](https://github.com/vercel/ms) for more details.\n- `cron`, for cron syntax, look up the [croner package](https://github.com/hexagon/croner)\n\nThe example below enqueue in both every 1 second and 5 minutes, since it's `cron`/`interval` settings.\n\n```typescript\nimport logger from '@adonisjs/core/services/logger'\nimport { BaseJob } from 'adonis-resque'\nexport default class Repeater extends BaseJob {\n    // enqueue job cronly\n    cron = '*/1 * * * * *'\n    // enqueue every five minutes\n    interval = '5m'\n    async perform() {\n        logger.info(`Repeater every 5 minutes / every seconds`)\n    }\n}\n```\n\n\n## Handle Failure Jobs\n\n### Job.onFailure\n\nYou can handle failure jobs by defining a `onFailure` method.\nOnce a job fails, it would be called before moving to the `failed` queue.\n\n```typescript\nimport { BaseJob, type ResqueFailure } from 'adonis-resque'\nclass Job extends BaseJob {\n      async onFailure(failure: ResqueFailure) {\n        console.log('resque job failured:', failure)\n    }\n}\n```\n\nThe definition of interface ResqueFailure\n\n```typescript\nexport interface ResqueFailure {\n    // Only the failure emitted by MultiWorker has a workerId\n    workerId?: number\n    queue: string\n    job: NodeResqueJob\n    failure: Error\n    duration: number\n}\n```\n\n\u003e [!TIP]\n\u003e If you are using `retry` plugin, the `onFailure` method will be called only if the job has exceeded the retry limit.\n\n### Failure Event\n\nAnother way to handle failure jobs is to listen to the `resque:failure` event.\n\ngo `start/events.ts` to handle.\n```typescript\nimport emitter from '@adonisjs/core/services/emitter'\n\nemitter.on('resque:failure', (failure) =\u003e {\n    console.error('resque:failure', failure)\n})\n```\n\n## Dependency Injection in Job Classes\nStarting from version 2+, dependency injection is now supported in class-based jobs. Since jobs run in the background, you cannot inject the current HttpContext.\n\nHere’s an example of a job that injects the logger:\n\n```typescript\nimport { inject } from '@adonisjs/core'\nimport type { Logger } from '@adonisjs/core/logger'\nimport { BaseJob } from 'adonis-resque'\n\n@inject()\nexport default class BasicExample extends BaseJob {\n    constructor(public logger: Logger) {\n        super()\n    }\n  \n    perform() {\n        this.logger.info('Basic example')\n        return 'gogogo'\n    }\n}\n```\n\n## Demonstration\n### Send Mail Job\n\nIn the Adonis Documentation, they use bullmq as mail queueing example.\nBut if we want to use `adonis-resque` for `mail.sendLater`, how to do?\n\n1. Create a Mail Job  \nRun `node ace make:job Mail` to create the mail job, then edit it in `app/jobs/mail.ts`\n\n```typescript\nimport { BaseJob } from 'adonis-resque'\nimport logger from '@adonisjs/core/services/logger'\nimport mail from '@adonisjs/mail/services/main'\nimport { MessageBodyTemplates, NodeMailerMessage } from '@adonisjs/mail/types'\n\ninterface Options {\n    mailMessage: {\n        message: NodeMailerMessage;\n        views: MessageBodyTemplates;\n    }\n    config: any\n}\nexport default class Mail extends BaseJob {\n    async perform(option: Options) {\n        const { messageId } = await mail.use('smtp')\n            .sendCompiled(option.mailMessage, option.config)\n        logger.info(`Email sent, id is ${messageId}`)\n    }\n}\n```\n\n2. Custom `mail.setMessenger` in a service provider  \nYou can add the below code snippet to a boot method of any service provider.\n\n```typescript\nconst mail = await this.app.container.make('mail.manager')\nmail.setMessenger(() =\u003e {\n  return {\n    async queue(mailMessage, sendConfig) {\n      return Mail.enqueue({ mailMessage, config: sendConfig })\n    }\n  }\n})\n```\n\n3. `mail.sendLater` is available now! Let's have a try. :shipit:\n```typescript\nawait mail.sendLater((message) =\u003e {\n  message.to('your-address@example.com', 'Your Name')\n  .subject('Hello from adonis-resque')\n  .html(`\u003cstrong\u003eCongratulations!\u003c/strong\u003e`)\n})\n```\n\n\u003e [!CAUTION]\n\u003e You should ensure `@adonisjs/mail` has a correct config, you'd better to test it first.\n\n\n## Plugin\n\nAdonis-resque encapsulated the default node-resque plugins in a smooth way, with the better typing support.\n\nThe default node-resque plugins are:\n\n- `Retry`\n- `JobLock`\n- `Retry`\n- `QueueLock`\n- `DelayQueueLock`\n- `Noop`\n\nYou can adding them to the `plugins` property of your job class, by `Plugin.\u003cPluginName\u003e({...pluginOptions})`\n\n### Plugin.jobLock\n\nJobLock plugin is used to prevent a job to be performed (hook in `beforePerform`), which has the same name, queue and args is already running.\n\nIf reEnqueue is `true`, the job will be put back (re-enqueue) with a delay \u003cenqueueTimeout\u003e.\n\n```typescript\nimport { BaseJob, Plugin } from \"adonis-resque\"\nimport logger from '@adonisjs/core/services/logger'\n\nexport default class ExampleJob extends BaseJob {\n    plugins = [\n        Plugin.jobLock({ reEnqueue: false, enqueueTimeout: 3000 })\n    ]\n    async perform() {\n        logger.info('Example job started')\n        await sleep(60000)\n        logger.info('Example job done')\n    }\n}\n\nfunction sleep(ms: number) {\n    return new Promise(resolve =\u003e setTimeout(resolve, ms));\n}\n```\n\n### Plugin.queueLock\n\nSimilar to jobLock, but it would be prevented before enqueue.\nIf a job with the same name, queue, and args is already in the queue, do not enqueue it again.\n\nQueueLock Options:\n\n```typescript\nexport interface QueueLockOptions {\n    /**\n     * in seconds\n     */\n    lockTimeout?: number\n    key?: LockKey\n}\n```\n### Plugin.delayQueueLock\n\nSame as queueLock, but it is for the delay queue.\n\n\u003e [!IMPORTANT]\n\u003e **How \"Prevented Before Enqueue\" Works?**  \n\u003e The `delayQueueLock` only prevents immediate enqueue operations; it doesn't prevent delayed enqueue operations, such as those using `enqueueIn` or `enqueueAt`.\n\u003e In `node-resque`, only non-delayed enqueue operations trigger the `beforeEnqueue` hook. If you use `enqueueIn` or `enqueueAt`, the hook is not triggered. \n\u003e [Here is source code](https://github.com/actionhero/node-resque/blob/a7eb5742df427aaf338efcc40579534ac458f57b/src/core/queue.ts#L86)\n\u003e \n\u003e Therefore, in the following code, the second operation won't be enqueued:\n\u003e ```typescript\n\u003e \n\u003e export default class ExampleJob extends BaseJob {\n\u003e     plugins = [\n\u003e         Plugin.delayQueueLock()\n\u003e     ]\n\u003e     async perform() {}\n\u003e }\n\u003e await ExampleJob.enqueueIn(1000)\n\u003e // won't enqueue to queue\n\u003e await ExampleJob.enqueue()\n\u003e ```\n\u003e However, in the following code, the job will perform twice, no matter if the `delayQueueLock` plugin is enabled or not:\n\u003e ```typescript\n\u003e await ExampleJob.enqueueIn(1000)\n\u003e await ExampleJob.enqueueIn(1500)\n\u003e ```\n\n\n### Plugin.retry\n\nIf a job fails, retry it \u003cretryLimit\u003e times before finally placing it into the failed queue\nYou can specify the retryDelay option to delay, or set the backoffStrategy to the delay ms array.\nNote:\nIt will retry by key, composed of queueName, jobName and args.\nNot retry by the enqueuing action.\n\n```typescript\nimport { BaseJob, Plugin } from \"adonis-resque\"\n\nexport default class ExampleJob extends BaseJob {\n    plugins = [\n        Plugin.retry({\n            retryLimit: 3,\n            backoffStrategy: [1000, 3000, 8000]\n        })\n    ]\n    async perform() {\n        const res = await fetch(`https://dummyjson.com/products/1`)\n        this.logger.info(`Response status is ${res.status}`)\n    }\n}\n```\n\n### Plugin.noop\n\nyou can customize the error logger by option `logger`\n\n### Custom Your Own Plugin\n\nYou can create your own plugin by extending the `BasePlugin` class,\nit also implements the `Plugin` abstract class from `node-resque`.\nSee more details in [node-resque plugins](https://github.com/actionhero/node-resque?tab=readme-ov-file#plugins).\n\n```typescript\nimport { BasePlugin } from \"adonis-resque\"\nexport default class MyPlugin extends BasePlugin {\n    /**\n     * Plugin options here\n     * with default values\n     */\n    options = {\n        foo: 'bar'\n    }\n    async beforeEnqueue() {\n    }\n    async afterEnqueue() {\n    }\n    async beforePerform(){\n    }\n    async afterPerform() {\n    }\n}\n```\n\nApplying it in your job class.\n\n```typescript\nimport { BaseJob } from \"adonis-resque\"\n// import MyPlugin from './my-plugin'\n\nclass ExampleJob extends BaseJob {\n    plugins = [\n        MyPlugin.create({ foo: 'baz' })\n    ]\n}\n```\n\n\n## Configuration\n\nHere is an example of `config/resque.ts`\n\n```typescript\n{\n    /**\n     * redis connection config from @adonisjs/redis\n     */\n    redisConnection: 'main',\n    /**\n     * run web \u0026 worker in same process, if enabled\n     * You need to run command node ace resque:start if it is turned off\n     *\n     * it's convenient but NOT Recommanded in production\n     * also, DO NOT enable for math-heavy jobs, even in the dev or staging environment.\n     * \n     */\n    runWorkerInWebEnv: true,\n    /**\n     * when runScheduler enabled, it starts with worker\n     * if you'd like to run scheduler in the separated processes\n     * please turn runScheduler off, and run command\n     * node ace resque:start --scheduler\n     */\n    runScheduler: true,\n    /**\n     * enable node-resque multiworker\n     * @docs https://github.com/actionhero/node-resque?tab=readme-ov-file#multi-worker\n     */\n    isMultiWorkerEnabled: true,\n    /**\n     * the first argument in MultiWorker constructor\n     */\n    multiWorkerOption: {\n        minTaskProcessors: 1,\n        maxTaskProcessors: 10\n    },\n    /**\n     * the argument for Worker constructor, if multiWorker is not enabled\n     */\n    workerOption: {\n    },\n    /**\n     * the default queue name for jobs to enqueue\n     */\n    queueNameForJobs: 'default',\n    /**\n     * queue name for workers to listen,\n     * is a string or an array of string\n     * setting a proper queue name could change their priorities \n     * e.g. queueNameForWorkers: \"high-priority, medium-priority, low-priority\"\n     * All the jobs in high-priority will be worked before any of the jobs in the other queues. \n     */\n    queueNameForWorkers: '*',\n    queueNameForWorkers: '*',\n    /**\n     * set null to use the default logger\n     */\n    logger: null,\n    // verbose mode for debugging\n    verbose: true\n}\n```\n\n## Concepts \u0026 Components\n### Queue\n\nQueue is a redis list under the hood, consumed(redis pop) in worker. \nEach job has a queueName, defined in Job class, default is `default`.\n\n```typescript\nclass Example extends BaseJob {\n  queueName = 'default'\n}\n```\nYou can enqueue jobs into queue from anywhere, .e.g, from a Adonis web controller or from another Job class: `Example.enqueue(...)`.\n\nThat means a redis push.\n\nFor failed jobs, they have been move to queue `failed`.\n\nThe `node-resque` queue object is exposed in a container: \n ```typescript\n const queue = await app.container.make('queue')\n ```\n\nYou can interact with it, find API here: https://node-resque.actionherojs.com/classes/Queue.html.\n\n#### Example: Getting a total count of pending jobs\n\n```typescript\nconst pendingJobsTotal = await queue.length(\u003cYourQueueName\u003e)\n```\n\n### Worker\n\nThe jobs you created are pulling and executed by workers actually.\nIt is a adonis ace command, long-running under the console environment.\n\nYou can start a worker by command: \n```bash\nnode ace resque:start --worker\n```\n\nIt has been executed by web server in default, so you don't need to run it.\n\n\u003e [!IMPORTANT]\n\u003e In the production environment, we don't recommend you to use the web server to run the worker.\n\u003e Instead, you should run the worker in the separated process, or multiple server.\n\u003e\n\nEvery worker has its own workerName, which composed of `os.hostname() + \":\" + process.pid + \"+\" + counter;`\n\n#### Multi Worker\nMultiWorker [comes from `node-resque`](https://github.com/actionhero/node-resque/tree/main?tab=readme-ov-file#multi-worker), is a pool manager for workers. It starts multiple workers in the same process, not in child process. Threfore, those workers have a same pid in their workerName.\n\nThis is designed for I/O intensive jobs, not CPU.\nSo don't get confused by the word `multi`. \n\n\u003e [!TIP]\n\u003e If you'd like to handle CPU intensive jobs, you can start multipe processes(by running the ace command), even on multipe machines.\n\nMulti worker is enabled by `isMultiWorkerEnabled` in config by default. If you'd like start a single worker, you can set the config to false, or  use the flag `--is-multi` to control:\n\n```bash\nnode ace resque:start --worker --is-multi=false\n```\n\n\n### Scheduler\n\nScheduler is a kind of specialized internal worker. It is a coordinator of the jobs.\n\nthe Utilities are:\n- Support croner \u0026 interval jobs\n- Process delayed job (`job.enqueueIn`/`job.enqueueAt`)\n- Checking stuck workers\n- General cluster cleanup\n- ...\n\n\u003e [!TIP]\n\u003e \n\u003e Scheduler could and should be run in many processes(machines), only one will be elected to be the `leader`, and actually do work; the others are backup.\n\u003e For more informations, see node-resque leader scheduler: https://github.com/actionhero/node-resque?tab=readme-ov-file#job-schedules\n\nBy default, scheduler starts with an worker together. You can modify `runScheduler` to `false` in config, to changing this behavior.\n\nTo start a stand alone scheduler, you can run \n```bash\nnode ace resque:start --worker=false --schedule\n```\n\n## Deployment\n\nResque is a distributed job queue system, it can be deloyed to separated processes or servers.\n\n### Development\n\nThe scheduler and multiworker are started with web server together.\nYou don't need to take any additional steps to make it work.\n\n### Production\n\nYou should disable the config `runWorkerInWebEnv`, and run `node ace resque:start` command in separated processes.\n\nIt is recommended to start mutiple schedules and workers.\nFor I/O intensive jobs, you should start multiWorker with `--is-multi` on; for CPU intensive jobs, no benefits from that.\n\nUsually, we build a docker image for both web server and jobs, start worker and scheduler by setting the entrypoint.\nThey could share the same other configures, like environment variables.\n\ndocker-compose.yml\n```yaml\n    ...\n    entrypoint: [\"node\", \"ace\", \"resque:start\", \"--worker\", \"--schedule\"]\n```\n\nFor people who don't use docker, you can also use `supervisord` or `pm2` to manage the processes.\n\n\n## Web UI\nnode-resque also compatible with some Resque Web UI, .e.g [resque-web](https://github.com/resque/resque-web)\n\nHere is `docker-compose.yml` an example\n```yaml\nservices:\n  redis:\n    image: redis\n  resque-web:\n    image: appwrite/resque-web:1.1.0\n    ports:\n      - \"5678:5678\"\n    environment:\n      - RESQUE_WEB_HOST=redis # (OPTIONAL - Use only if different than the default 127.0.0.1)\n      - RESQUE_WEB_PORT=6379  # (OPTIONAL - Use only if different the default 6379)\n      - RESQUE_WEB_HTTP_BASIC_AUTH_USER= # (OPTIONAL - if not set no password used)\n      - RESQUE_WEB_HTTP_BASIC_AUTH_PASSWORD=  # (OPTIONAL - if not set no password used)\n    depends_on:\n      - redis\n    restart: unless-stopped\n```\n\nif redis server has a password, you can add a entrypoint\n\n```yaml\n    entrypoint:\n      - resque-web\n      - -FL\n      - -r\n      # Change your redis password here,\n      # default redis user is default\n      - \"redis://\u003credis-user\u003e:\u003credis-password\u003e@\u003chost\u003e:\u003cport\u003e\"\n      - /config.ru\n```\n\n![Web UI](https://i.imgur.com/nN2d9ak.png)\n\n## Notice 1: for the graceful exit\nresque require the graceful exit, or schedulers would waiting for a leader election.\n\nnode-resque may not exit in dev environment if you exit by `ctrl+c`.\nyou can change `bin/server.ts`\n```typescript\napp.listenIf(app.managedByPm2, 'SIGINT', () =\u003e app.terminate())\n```\nto \n```typescript\napp.listen('SIGINT', () =\u003e app.terminate())\n```\n\nif adonis dev server terminated but process still there, you can send SIGTERM signal to all node process(on macOS) `killall node`\n\nYou can also check the redis key `resque:resque_scheduler_leader_lock`, which value is scheduler name contains pid of the leader process. it should be release once server terminated.\n\n## Notice 2: Job does not `@inject`able\nSince our job is a [Thenable class](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise#thenables), that made it not able be inject([related issue](https://github.com/adonisjs/fold/issues/63)), which means `@inject` decorator won't work.\n\nYou can use `app.container.make()` in job instead.\n\n## Who's Using\n[Create an issue](https://github.com/shiny/adonis-resque/issues/new) to submit your project.\n\n\u003cdiv\u003e\n\u003ca href=\"https://u301.com/\"\u003e\u003cimg src=\"https://u301.com/img/u301-logo.png\" style=\"width:120px\" /\u003e\u003c/a\u003e\n\u003c/div\u003e\n\n## Contributors\n\nThis project is contributed by u301 team for giving back to the AdonisJS community.\n\n## Reference\n\n- [node-resque](https://github.com/actionhero/node-resque)\n\n## Migration from v1 to v2\nIn the latest version of AdonisJS, the previous method of directly creating an instance of @adonisjs/logger (used in v1) is no longer compatible. \nTo address this, adonis-resque has been upgraded to v2, with changes to the API interface.\n\n### Changes in ver 2\n\n#### this.logger Removed\n`this.logger` removed in Job. You can use `import logger from '@adonisjs/core/services/logger'` instead.\n\n#### Chainable Methods Removed\nIn v1, you could use chainable calls like `await ExampleJob.enqueue(...args).in(1000)`. However, this feature has been removed in v2. Now, you should use `await ExampleJob.enqueueIn(1000, ...args)` instead. Additionally, these methods now return a Promise, whereas they previously only returned this. \n\nThe following methods have been removed:\n\n- in\n- at\n- The static method queue()\n\nSince Resque's functionality is relatively simple, the benefits of chainable calls are minimal, and they also hinder Adonis's dependency injection capabilities.\n\n#### Dependency Injection Now Available in Job Files\nWith the removal of chainable calls, dependency injection is now available in job files. However, keep in mind that because jobs run in the background, the `HttpContext` cannot be injected.\n\n## License\nMIT\n\n[![FOSSA Status](https://app.fossa.com/api/projects/git%2Bgithub.com%2Fshiny%2Fadonis-resque.svg?type=large\u0026issueType=license)](https://app.fossa.com/projects/git%2Bgithub.com%2Fshiny%2Fadonis-resque?ref=badge_large\u0026issueType=license)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshiny%2Fadonis-resque","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fshiny%2Fadonis-resque","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fshiny%2Fadonis-resque/lists"}