@adonisjs/queue 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +9 -0
- package/README.md +38 -0
- package/build/bin/test.d.ts +1 -0
- package/build/bin/test.js +30 -0
- package/build/commands/commands.json +1 -0
- package/build/commands/main.d.ts +4 -0
- package/build/commands/main.js +36 -0
- package/build/commands/make_job.d.ts +9 -0
- package/build/commands/make_job.js +33 -0
- package/build/commands/queue_scheduler_clear.d.ts +8 -0
- package/build/commands/queue_scheduler_clear.js +34 -0
- package/build/commands/queue_scheduler_list.d.ts +9 -0
- package/build/commands/queue_scheduler_list.js +54 -0
- package/build/commands/queue_scheduler_remove.d.ts +9 -0
- package/build/commands/queue_scheduler_remove.js +42 -0
- package/build/commands/queue_work.d.ts +9 -0
- package/build/commands/queue_work.js +41 -0
- package/build/configure.d.ts +5 -0
- package/build/configure.js +66 -0
- package/build/index.d.ts +5 -0
- package/build/index.js +15 -0
- package/build/providers/queue_provider.d.ts +8 -0
- package/build/providers/queue_provider.js +53 -0
- package/build/services/queue.d.ts +3 -0
- package/build/services/queue.js +14 -0
- package/build/src/define_config.d.ts +5 -0
- package/build/src/define_config.js +14 -0
- package/build/src/drivers.d.ts +33 -0
- package/build/src/drivers.js +42 -0
- package/build/src/types/extended.d.ts +6 -0
- package/build/src/types/extended.js +9 -0
- package/build/src/types/main.d.ts +1 -0
- package/build/src/types/main.js +9 -0
- package/build/stubs/config/queue.stub +29 -0
- package/build/stubs/main.d.ts +1 -0
- package/build/stubs/main.js +10 -0
- package/build/stubs/make/job/main.stub +29 -0
- package/build/stubs/migration.stub +53 -0
- package/build/tests/configure.spec.d.ts +1 -0
- package/build/tests/configure.spec.js +144 -0
- package/package.json +124 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
# The MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Romain Lanz, AdonisJS Core Team, contributors
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
|
6
|
+
|
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
|
8
|
+
|
|
9
|
+
THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# @adonisjs/queue
|
|
2
|
+
|
|
3
|
+
<br />
|
|
4
|
+
|
|
5
|
+
[![gh-workflow-image]][gh-workflow-url] [![npm-image]][npm-url] ![][typescript-image] [![license-image]][license-url]
|
|
6
|
+
|
|
7
|
+
## Introduction
|
|
8
|
+
|
|
9
|
+
Queue system for AdonisJS applications, powered by [@boringnode/queue](https://github.com/boringnode/queue). Process background jobs with support for multiple drivers (Redis, Database), job retries, scheduling, and more.
|
|
10
|
+
|
|
11
|
+
## Official Documentation
|
|
12
|
+
|
|
13
|
+
The documentation is available on the [AdonisJS website](https://docs.adonisjs.com/guides/digging-deeper/queues)
|
|
14
|
+
|
|
15
|
+
## Contributing
|
|
16
|
+
|
|
17
|
+
One of the primary goals of AdonisJS is to have a vibrant community of users and contributors who believes in the principles of the framework.
|
|
18
|
+
|
|
19
|
+
We encourage you to read the [contribution guide](https://github.com/adonisjs/.github/blob/main/docs/CONTRIBUTING.md) before contributing to the framework.
|
|
20
|
+
|
|
21
|
+
## Code of Conduct
|
|
22
|
+
|
|
23
|
+
In order to ensure that the AdonisJS community is welcoming to all, please review and abide by the [Code of Conduct](https://github.com/adonisjs/.github/blob/main/docs/CODE_OF_CONDUCT.md).
|
|
24
|
+
|
|
25
|
+
## License
|
|
26
|
+
|
|
27
|
+
AdonisJS Queue is open-sourced software licensed under the [MIT license](LICENSE.md).
|
|
28
|
+
|
|
29
|
+
[gh-workflow-image]: https://img.shields.io/github/actions/workflow/status/adonisjs/queue/checks.yml?style=for-the-badge
|
|
30
|
+
[gh-workflow-url]: https://github.com/adonisjs/queue/actions/workflows/checks.yml "Github action"
|
|
31
|
+
|
|
32
|
+
[npm-image]: https://img.shields.io/npm/v/@adonisjs/queue/latest.svg?style=for-the-badge&logo=npm
|
|
33
|
+
[npm-url]: https://www.npmjs.com/package/@adonisjs/queue/v/latest "npm"
|
|
34
|
+
|
|
35
|
+
[typescript-image]: https://img.shields.io/badge/Typescript-294E80.svg?style=for-the-badge&logo=typescript
|
|
36
|
+
|
|
37
|
+
[license-url]: LICENSE.md
|
|
38
|
+
[license-image]: https://img.shields.io/github/license/adonisjs/queue?style=for-the-badge
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { assert } from '@japa/assert';
|
|
2
|
+
import { fileSystem } from '@japa/file-system';
|
|
3
|
+
import { processCLIArgs, configure, run } from '@japa/runner';
|
|
4
|
+
/*
|
|
5
|
+
|--------------------------------------------------------------------------
|
|
6
|
+
| Configure tests
|
|
7
|
+
|--------------------------------------------------------------------------
|
|
8
|
+
|
|
|
9
|
+
| The configure method accepts the configuration to configure the Japa
|
|
10
|
+
| tests runner.
|
|
11
|
+
|
|
|
12
|
+
| The first method call "processCLIArgs" process the command line arguments
|
|
13
|
+
| and turns them into a config object. Using this method is not mandatory.
|
|
14
|
+
|
|
|
15
|
+
| Please consult japa.dev/runner-config for the config docs.
|
|
16
|
+
*/
|
|
17
|
+
processCLIArgs(process.argv.slice(2));
|
|
18
|
+
configure({
|
|
19
|
+
files: ['tests/**/*.spec.ts'],
|
|
20
|
+
plugins: [assert(), fileSystem({ autoClean: true })],
|
|
21
|
+
});
|
|
22
|
+
/*
|
|
23
|
+
|--------------------------------------------------------------------------
|
|
24
|
+
| Run tests
|
|
25
|
+
|--------------------------------------------------------------------------
|
|
26
|
+
|
|
|
27
|
+
| The following "run" method is required to execute all the tests.
|
|
28
|
+
|
|
|
29
|
+
*/
|
|
30
|
+
await run();
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"commands":[{"commandName":"make:job","description":"Create a new job class","help":"","namespace":"make","aliases":[],"flags":[],"args":[{"name":"name","argumentName":"name","required":true,"description":"Name of the job","type":"string"}],"options":{"allowUnknownFlags":true},"filePath":"make_job.js"},{"commandName":"queue:scheduler:clear","description":"Remove all scheduled jobs","help":"","namespace":"queue","aliases":[],"flags":[],"args":[],"options":{"startApp":true},"filePath":"queue_scheduler_clear.js"},{"commandName":"queue:scheduler:list","description":"List all scheduled jobs","help":"","namespace":"queue","aliases":[],"flags":[{"name":"status","flagName":"status","required":false,"type":"string","description":"Filter by status (active, paused)","alias":"s"}],"args":[],"options":{"startApp":true},"filePath":"queue_scheduler_list.js"},{"commandName":"queue:scheduler:remove","description":"Remove a scheduled job by ID","help":"","namespace":"queue","aliases":[],"flags":[],"args":[{"name":"id","argumentName":"id","required":true,"description":"ID of the schedule to remove","type":"string"}],"options":{"startApp":true},"filePath":"queue_scheduler_remove.js"},{"commandName":"queue:work","description":"Start processing jobs from the queue","help":"","namespace":"queue","aliases":[],"flags":[{"name":"queue","flagName":"queue","required":false,"type":"string","description":"Comma-separated list of queues to process","alias":"q"}],"args":[],"options":{"startApp":true,"staysAlive":true},"filePath":"queue_work.js"}],"version":1}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* In-memory cache of commands after they have been loaded
|
|
5
|
+
*/
|
|
6
|
+
let commandsMetaData
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Reads the commands from the "./commands.json" file. Since, the commands.json
|
|
10
|
+
* file is generated automatically, we do not have to validate its contents
|
|
11
|
+
*/
|
|
12
|
+
export async function getMetaData() {
|
|
13
|
+
if (commandsMetaData) {
|
|
14
|
+
return commandsMetaData
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const commandsIndex = await readFile(new URL('./commands.json', import.meta.url), 'utf-8')
|
|
18
|
+
commandsMetaData = JSON.parse(commandsIndex).commands
|
|
19
|
+
|
|
20
|
+
return commandsMetaData
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Imports the command by lookingup its path from the commands
|
|
25
|
+
* metadata
|
|
26
|
+
*/
|
|
27
|
+
export async function getCommand(metaData) {
|
|
28
|
+
const commands = await getMetaData()
|
|
29
|
+
const command = commands.find(({ commandName }) => metaData.commandName === commandName)
|
|
30
|
+
if (!command) {
|
|
31
|
+
return null
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
const { default: commandConstructor } = await import(new URL(command.filePath, import.meta.url).href)
|
|
35
|
+
return commandConstructor
|
|
36
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BaseCommand } from '@adonisjs/core/ace';
|
|
2
|
+
import type { CommandOptions } from '@adonisjs/core/types/ace';
|
|
3
|
+
export default class MakeJob extends BaseCommand {
|
|
4
|
+
static commandName: string;
|
|
5
|
+
static description: string;
|
|
6
|
+
static options: CommandOptions;
|
|
7
|
+
name: string;
|
|
8
|
+
run(): Promise<void>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/queue
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
10
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
11
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
12
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
13
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
14
|
+
};
|
|
15
|
+
import { args, BaseCommand } from '@adonisjs/core/ace';
|
|
16
|
+
import { stubsRoot } from '../stubs/main.js';
|
|
17
|
+
export default class MakeJob extends BaseCommand {
|
|
18
|
+
static commandName = 'make:job';
|
|
19
|
+
static description = 'Create a new job class';
|
|
20
|
+
static options = {
|
|
21
|
+
allowUnknownFlags: true,
|
|
22
|
+
};
|
|
23
|
+
async run() {
|
|
24
|
+
const codemods = await this.createCodemods();
|
|
25
|
+
await codemods.makeUsingStub(stubsRoot, 'make/job/main.stub', {
|
|
26
|
+
flags: this.parsed.flags,
|
|
27
|
+
entity: this.app.generators.createEntity(this.name),
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
__decorate([
|
|
32
|
+
args.string({ description: 'Name of the job' })
|
|
33
|
+
], MakeJob.prototype, "name", void 0);
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { BaseCommand } from '@adonisjs/core/ace';
|
|
2
|
+
import type { CommandOptions } from '@adonisjs/core/types/ace';
|
|
3
|
+
export default class QueueSchedulerClear extends BaseCommand {
|
|
4
|
+
static commandName: string;
|
|
5
|
+
static description: string;
|
|
6
|
+
static options: CommandOptions;
|
|
7
|
+
run(): Promise<void>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/queue
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
import { BaseCommand } from '@adonisjs/core/ace';
|
|
10
|
+
export default class QueueSchedulerClear extends BaseCommand {
|
|
11
|
+
static commandName = 'queue:scheduler:clear';
|
|
12
|
+
static description = 'Remove all scheduled jobs';
|
|
13
|
+
static options = {
|
|
14
|
+
startApp: true,
|
|
15
|
+
};
|
|
16
|
+
async run() {
|
|
17
|
+
const { Schedule } = await import('@boringnode/queue');
|
|
18
|
+
const schedules = await Schedule.list();
|
|
19
|
+
if (schedules.length === 0) {
|
|
20
|
+
this.logger.info('No schedules to clear');
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
if (this.app.inProduction) {
|
|
24
|
+
const confirmed = await this.prompt.confirm(`Are you sure you want to remove all ${schedules.length} schedules?`);
|
|
25
|
+
if (!confirmed) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
for (const schedule of schedules) {
|
|
30
|
+
await schedule.delete();
|
|
31
|
+
}
|
|
32
|
+
this.logger.success(`Removed ${schedules.length} schedules successfully`);
|
|
33
|
+
}
|
|
34
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BaseCommand } from '@adonisjs/core/ace';
|
|
2
|
+
import type { CommandOptions } from '@adonisjs/core/types/ace';
|
|
3
|
+
export default class QueueSchedulerList extends BaseCommand {
|
|
4
|
+
static commandName: string;
|
|
5
|
+
static description: string;
|
|
6
|
+
static options: CommandOptions;
|
|
7
|
+
status?: string;
|
|
8
|
+
run(): Promise<void>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/queue
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
10
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
11
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
12
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
13
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
14
|
+
};
|
|
15
|
+
import { BaseCommand, flags } from '@adonisjs/core/ace';
|
|
16
|
+
export default class QueueSchedulerList extends BaseCommand {
|
|
17
|
+
static commandName = 'queue:scheduler:list';
|
|
18
|
+
static description = 'List all scheduled jobs';
|
|
19
|
+
static options = {
|
|
20
|
+
startApp: true,
|
|
21
|
+
};
|
|
22
|
+
async run() {
|
|
23
|
+
const { Schedule } = await import('@boringnode/queue');
|
|
24
|
+
const options = {};
|
|
25
|
+
if (this.status === 'active' || this.status === 'paused') {
|
|
26
|
+
options.status = this.status;
|
|
27
|
+
}
|
|
28
|
+
const schedules = await Schedule.list(options);
|
|
29
|
+
if (schedules.length === 0) {
|
|
30
|
+
this.logger.info('No schedules found');
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
const table = this.ui.table();
|
|
34
|
+
table.head(['ID', 'Job', 'Schedule', 'Status', 'Run Count', 'Next Run', 'Last Run']);
|
|
35
|
+
for (const schedule of schedules) {
|
|
36
|
+
const scheduleExpr = schedule.cronExpression ?? `every ${schedule.everyMs}ms`;
|
|
37
|
+
const nextRun = schedule.nextRunAt?.toISOString() ?? 'N/A';
|
|
38
|
+
const lastRun = schedule.lastRunAt?.toISOString() ?? 'Never';
|
|
39
|
+
table.row([
|
|
40
|
+
schedule.id,
|
|
41
|
+
schedule.jobName,
|
|
42
|
+
scheduleExpr,
|
|
43
|
+
schedule.status,
|
|
44
|
+
String(schedule.runCount),
|
|
45
|
+
nextRun,
|
|
46
|
+
lastRun,
|
|
47
|
+
]);
|
|
48
|
+
}
|
|
49
|
+
table.render();
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
__decorate([
|
|
53
|
+
flags.string({ description: 'Filter by status (active, paused)', alias: 's' })
|
|
54
|
+
], QueueSchedulerList.prototype, "status", void 0);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BaseCommand } from '@adonisjs/core/ace';
|
|
2
|
+
import type { CommandOptions } from '@adonisjs/core/types/ace';
|
|
3
|
+
export default class QueueSchedulerRemove extends BaseCommand {
|
|
4
|
+
static commandName: string;
|
|
5
|
+
static description: string;
|
|
6
|
+
static options: CommandOptions;
|
|
7
|
+
id: string;
|
|
8
|
+
run(): Promise<void>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/queue
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
10
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
11
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
12
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
13
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
14
|
+
};
|
|
15
|
+
import { args, BaseCommand } from '@adonisjs/core/ace';
|
|
16
|
+
export default class QueueSchedulerRemove extends BaseCommand {
|
|
17
|
+
static commandName = 'queue:scheduler:remove';
|
|
18
|
+
static description = 'Remove a scheduled job by ID';
|
|
19
|
+
static options = {
|
|
20
|
+
startApp: true,
|
|
21
|
+
};
|
|
22
|
+
async run() {
|
|
23
|
+
const { Schedule } = await import('@boringnode/queue');
|
|
24
|
+
const schedule = await Schedule.find(this.id);
|
|
25
|
+
if (!schedule) {
|
|
26
|
+
this.logger.error(`Schedule "${this.id}" not found`);
|
|
27
|
+
this.exitCode = 1;
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
if (this.app.inProduction) {
|
|
31
|
+
const confirmed = await this.prompt.confirm(`Are you sure you want to remove schedule "${this.id}"?`);
|
|
32
|
+
if (!confirmed) {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
await schedule.delete();
|
|
37
|
+
this.logger.success(`Schedule "${this.id}" removed successfully`);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
__decorate([
|
|
41
|
+
args.string({ description: 'ID of the schedule to remove' })
|
|
42
|
+
], QueueSchedulerRemove.prototype, "id", void 0);
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { BaseCommand } from '@adonisjs/core/ace';
|
|
2
|
+
import type { CommandOptions } from '@adonisjs/core/types/ace';
|
|
3
|
+
export default class QueueWork extends BaseCommand {
|
|
4
|
+
static commandName: string;
|
|
5
|
+
static description: string;
|
|
6
|
+
static options: CommandOptions;
|
|
7
|
+
queue?: string;
|
|
8
|
+
run(): Promise<void>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/queue
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
|
|
10
|
+
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
|
|
11
|
+
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
|
|
12
|
+
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
|
|
13
|
+
return c > 3 && r && Object.defineProperty(target, key, r), r;
|
|
14
|
+
};
|
|
15
|
+
import { flags, BaseCommand } from '@adonisjs/core/ace';
|
|
16
|
+
export default class QueueWork extends BaseCommand {
|
|
17
|
+
static commandName = 'queue:work';
|
|
18
|
+
static description = 'Start processing jobs from the queue';
|
|
19
|
+
static options = {
|
|
20
|
+
startApp: true,
|
|
21
|
+
staysAlive: true,
|
|
22
|
+
};
|
|
23
|
+
async run() {
|
|
24
|
+
const { Worker } = await import('@boringnode/queue');
|
|
25
|
+
const config = this.app.config.get('queue');
|
|
26
|
+
/**
|
|
27
|
+
* Commit the router to ensure all routes are registered.
|
|
28
|
+
* This is required when jobs dispatch HTTP requests or
|
|
29
|
+
* use URL generation.
|
|
30
|
+
*/
|
|
31
|
+
const router = await this.app.container.make('router');
|
|
32
|
+
router.commit();
|
|
33
|
+
const queues = this.queue ? this.queue.split(',').map((q) => q.trim()) : ['default'];
|
|
34
|
+
this.logger.info(`Starting worker for queues: ${queues.join(', ')}`);
|
|
35
|
+
const worker = new Worker(config);
|
|
36
|
+
await worker.start(queues);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
__decorate([
|
|
40
|
+
flags.string({ description: 'Comma-separated list of queues to process', alias: 'q' })
|
|
41
|
+
], QueueWork.prototype, "queue", void 0);
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/queue
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
import { stubsRoot } from './stubs/main.js';
|
|
10
|
+
const DRIVERS = ['redis', 'database'];
|
|
11
|
+
const DRIVERS_INFO = {
|
|
12
|
+
redis: {},
|
|
13
|
+
database: {},
|
|
14
|
+
};
|
|
15
|
+
/**
|
|
16
|
+
* Configures the package
|
|
17
|
+
*/
|
|
18
|
+
export async function configure(command) {
|
|
19
|
+
const driver = await command.prompt.choice('Select the queue driver you plan to use', ['redis', 'database'], { hint: 'You can always change it later' });
|
|
20
|
+
const codemods = await command.createCodemods();
|
|
21
|
+
/**
|
|
22
|
+
* Register provider and command
|
|
23
|
+
*/
|
|
24
|
+
await codemods.updateRcFile((rcFile) => {
|
|
25
|
+
rcFile.addProvider('@adonisjs/queue/queue_provider').addCommand('@adonisjs/queue/commands');
|
|
26
|
+
});
|
|
27
|
+
/**
|
|
28
|
+
* Define environment variables
|
|
29
|
+
*/
|
|
30
|
+
await codemods.defineEnvVariables({ QUEUE_DRIVER: driver });
|
|
31
|
+
/**
|
|
32
|
+
* Define environment validations
|
|
33
|
+
*/
|
|
34
|
+
await codemods.defineEnvValidations({
|
|
35
|
+
variables: {
|
|
36
|
+
QUEUE_DRIVER: `Env.schema.enum(['redis', 'database', 'sync'] as const)`,
|
|
37
|
+
},
|
|
38
|
+
leadingComment: 'Variables for configuring @adonisjs/queue',
|
|
39
|
+
});
|
|
40
|
+
const { envVars, envValidations } = DRIVERS_INFO[driver];
|
|
41
|
+
if (envVars) {
|
|
42
|
+
await codemods.defineEnvVariables(envVars);
|
|
43
|
+
}
|
|
44
|
+
if (envValidations) {
|
|
45
|
+
await codemods.defineEnvValidations({ variables: envValidations });
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Publish config file
|
|
49
|
+
*/
|
|
50
|
+
await codemods.makeUsingStub(stubsRoot, 'config/queue.stub', { driver });
|
|
51
|
+
/**
|
|
52
|
+
* Create migration for database driver
|
|
53
|
+
*/
|
|
54
|
+
if (driver === 'database') {
|
|
55
|
+
const shouldPublishMigration = await command.prompt.confirm('Do you want to publish the migration for the queue tables?', { hint: 'Tables are auto-created by default, but you can manage them manually' });
|
|
56
|
+
if (shouldPublishMigration) {
|
|
57
|
+
await codemods.makeUsingStub(stubsRoot, 'migration.stub', {
|
|
58
|
+
entity: command.app.generators.createEntity('queue'),
|
|
59
|
+
migration: {
|
|
60
|
+
folder: 'database/migrations',
|
|
61
|
+
fileName: `${new Date().getTime()}_create_queue_tables.ts`,
|
|
62
|
+
},
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
package/build/index.d.ts
ADDED
package/build/index.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/queue
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
// Re-export everything from @boringnode/queue
|
|
10
|
+
export * from '@boringnode/queue';
|
|
11
|
+
// AdonisJS specific exports
|
|
12
|
+
export { configure } from './configure.js';
|
|
13
|
+
export { defineConfig } from './src/define_config.js';
|
|
14
|
+
export { drivers } from './src/drivers.js';
|
|
15
|
+
export { stubsRoot } from './stubs/main.js';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import '../src/types/extended.js';
|
|
2
|
+
import type { ApplicationService } from '@adonisjs/core/types';
|
|
3
|
+
export default class QueueProvider {
|
|
4
|
+
protected app: ApplicationService;
|
|
5
|
+
constructor(app: ApplicationService);
|
|
6
|
+
register(): void;
|
|
7
|
+
shutdown(): Promise<void>;
|
|
8
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/queue
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
import '../src/types/extended.js';
|
|
10
|
+
export default class QueueProvider {
|
|
11
|
+
app;
|
|
12
|
+
constructor(app) {
|
|
13
|
+
this.app = app;
|
|
14
|
+
}
|
|
15
|
+
register() {
|
|
16
|
+
this.app.container.singleton('queue.manager', async () => {
|
|
17
|
+
const { QueueManager } = await import('@boringnode/queue');
|
|
18
|
+
const config = this.app.config.get('queue');
|
|
19
|
+
/**
|
|
20
|
+
* Resolve adapter factories from config providers
|
|
21
|
+
*/
|
|
22
|
+
const resolvedAdapters = {};
|
|
23
|
+
for (const [name, adapterConfig] of Object.entries(config.adapters)) {
|
|
24
|
+
if (typeof adapterConfig === 'function') {
|
|
25
|
+
resolvedAdapters[name] = adapterConfig;
|
|
26
|
+
}
|
|
27
|
+
else {
|
|
28
|
+
resolvedAdapters[name] = await adapterConfig.resolver(this.app);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Inject jobFactory if not already defined.
|
|
33
|
+
* This enables automatic dependency injection for job classes.
|
|
34
|
+
*/
|
|
35
|
+
const jobFactory = config.jobFactory ??
|
|
36
|
+
(async (JobClass, payload, context) => {
|
|
37
|
+
return this.app.container.make(JobClass, [payload, context]);
|
|
38
|
+
});
|
|
39
|
+
const logger = await this.app.container.make('logger');
|
|
40
|
+
await QueueManager.init({
|
|
41
|
+
...config,
|
|
42
|
+
adapters: resolvedAdapters,
|
|
43
|
+
jobFactory,
|
|
44
|
+
logger: config.logger ?? logger,
|
|
45
|
+
});
|
|
46
|
+
return QueueManager;
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
async shutdown() {
|
|
50
|
+
const queueManager = await this.app.container.make('queue.manager');
|
|
51
|
+
await queueManager.destroy();
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/queue
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
import app from '@adonisjs/core/services/app';
|
|
10
|
+
let queue;
|
|
11
|
+
await app.booted(async () => {
|
|
12
|
+
queue = await app.container.make('queue.manager');
|
|
13
|
+
});
|
|
14
|
+
export { queue as default };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/queue
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
/**
|
|
10
|
+
* Define queue configuration with type-safety.
|
|
11
|
+
*/
|
|
12
|
+
export function defineConfig(config) {
|
|
13
|
+
return config;
|
|
14
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { ConfigProvider } from '@adonisjs/core/types';
|
|
2
|
+
import type { RedisConnections } from '@adonisjs/redis/types';
|
|
3
|
+
import type { Adapter } from '@boringnode/queue/types';
|
|
4
|
+
type AdapterFactory = () => Adapter;
|
|
5
|
+
/**
|
|
6
|
+
* Queue drivers that integrate with AdonisJS services.
|
|
7
|
+
*
|
|
8
|
+
* These drivers use `configProvider.create()` to lazily resolve
|
|
9
|
+
* connections from the AdonisJS container.
|
|
10
|
+
*/
|
|
11
|
+
export declare const drivers: {
|
|
12
|
+
/**
|
|
13
|
+
* Redis driver using @adonisjs/redis connection.
|
|
14
|
+
* Requires @adonisjs/redis to be installed and configured.
|
|
15
|
+
*/
|
|
16
|
+
redis: (config?: {
|
|
17
|
+
connectionName?: keyof RedisConnections;
|
|
18
|
+
}) => ConfigProvider<AdapterFactory>;
|
|
19
|
+
/**
|
|
20
|
+
* Database driver using @adonisjs/lucid connection.
|
|
21
|
+
* Requires @adonisjs/lucid to be installed and configured.
|
|
22
|
+
*/
|
|
23
|
+
database: (config?: {
|
|
24
|
+
connectionName?: string;
|
|
25
|
+
tableName?: string;
|
|
26
|
+
}) => ConfigProvider<AdapterFactory>;
|
|
27
|
+
/**
|
|
28
|
+
* Sync driver for testing (executes jobs immediately).
|
|
29
|
+
* No external dependencies required.
|
|
30
|
+
*/
|
|
31
|
+
sync: () => ConfigProvider<AdapterFactory>;
|
|
32
|
+
};
|
|
33
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/queue
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
/// <reference types="@adonisjs/redis/redis_provider" />
|
|
10
|
+
/// <reference types="@adonisjs/lucid/database_provider" />
|
|
11
|
+
import { configProvider } from '@adonisjs/core';
|
|
12
|
+
/**
|
|
13
|
+
* Queue drivers that integrate with AdonisJS services.
|
|
14
|
+
*
|
|
15
|
+
* These drivers use `configProvider.create()` to lazily resolve
|
|
16
|
+
* connections from the AdonisJS container.
|
|
17
|
+
*/
|
|
18
|
+
export const drivers = {
|
|
19
|
+
redis(config) {
|
|
20
|
+
return configProvider.create(async (app) => {
|
|
21
|
+
const redis = await app.container.make('redis');
|
|
22
|
+
const { redis: redisAdapter } = await import('@boringnode/queue/drivers/redis_adapter');
|
|
23
|
+
const connection = redis.connection(config?.connectionName);
|
|
24
|
+
return redisAdapter(connection.ioConnection);
|
|
25
|
+
});
|
|
26
|
+
},
|
|
27
|
+
database(config) {
|
|
28
|
+
return configProvider.create(async (app) => {
|
|
29
|
+
const db = await app.container.make('lucid.db');
|
|
30
|
+
const { knex } = await import('@boringnode/queue/drivers/knex_adapter');
|
|
31
|
+
const connectionName = config?.connectionName || db.primaryConnectionName;
|
|
32
|
+
const connection = db.connection(connectionName);
|
|
33
|
+
return knex(connection.getWriteClient(), config?.tableName);
|
|
34
|
+
});
|
|
35
|
+
},
|
|
36
|
+
sync() {
|
|
37
|
+
return configProvider.create(async () => {
|
|
38
|
+
const { sync } = await import('@boringnode/queue/drivers/sync_adapter');
|
|
39
|
+
return sync();
|
|
40
|
+
});
|
|
41
|
+
},
|
|
42
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from '@boringnode/queue/types';
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{{{
|
|
2
|
+
exports({ to: app.configPath('queue.ts') })
|
|
3
|
+
}}}
|
|
4
|
+
import env from '#start/env'
|
|
5
|
+
import { defineConfig, drivers } from '@adonisjs/queue'
|
|
6
|
+
|
|
7
|
+
export default defineConfig({
|
|
8
|
+
default: env.get('QUEUE_DRIVER', '{{driver}}'),
|
|
9
|
+
|
|
10
|
+
adapters: {
|
|
11
|
+
{{#if driver === 'redis'}}
|
|
12
|
+
redis: drivers.redis({
|
|
13
|
+
connectionName: 'main',
|
|
14
|
+
}),
|
|
15
|
+
{{#elif driver === 'database'}}
|
|
16
|
+
database: drivers.database({
|
|
17
|
+
connectionName: 'primary',
|
|
18
|
+
}),
|
|
19
|
+
{{/if}}
|
|
20
|
+
sync: drivers.sync(),
|
|
21
|
+
},
|
|
22
|
+
|
|
23
|
+
worker: {
|
|
24
|
+
concurrency: 5,
|
|
25
|
+
idleDelay: '2s',
|
|
26
|
+
},
|
|
27
|
+
|
|
28
|
+
locations: ['./app/jobs/**/*.ts'],
|
|
29
|
+
})
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const stubsRoot: string;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/queue
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
import { getDirname } from '@poppinss/utils';
|
|
10
|
+
export const stubsRoot = getDirname(import.meta.url);
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
{{#var jobName = string(entity.name).pascalCase().toString()}}
|
|
2
|
+
{{#var jobFileName = string(entity.name).snakeCase().toString()}}
|
|
3
|
+
{{{
|
|
4
|
+
exports({
|
|
5
|
+
to: app.makePath('app/jobs', entity.path, jobFileName + '.ts')
|
|
6
|
+
})
|
|
7
|
+
}}}
|
|
8
|
+
import { Job } from '@adonisjs/queue'
|
|
9
|
+
import type { JobOption } from '@adonisjs/queue/types'
|
|
10
|
+
|
|
11
|
+
interface {{ jobName }}Payload {
|
|
12
|
+
// Define your payload type here
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export default class {{ jobName }} extends Job<{{ jobName }}Payload> {
|
|
16
|
+
static options: JobOption = {
|
|
17
|
+
queue: 'default',
|
|
18
|
+
maxRetries: 3,
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
async execute() {
|
|
22
|
+
// Your job logic here
|
|
23
|
+
console.log('Processing {{ jobName }}', this.payload)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
async failed(error: Error) {
|
|
27
|
+
console.error('{{ jobName }} failed:', error.message)
|
|
28
|
+
}
|
|
29
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
{{{
|
|
2
|
+
exports({
|
|
3
|
+
to: app.makePath(migration.folder, entity.path, migration.fileName)
|
|
4
|
+
})
|
|
5
|
+
}}}
|
|
6
|
+
import { BaseSchema } from '@adonisjs/lucid/schema'
|
|
7
|
+
|
|
8
|
+
export default class extends BaseSchema {
|
|
9
|
+
async up() {
|
|
10
|
+
/**
|
|
11
|
+
* Jobs table - stores pending, active, and delayed jobs
|
|
12
|
+
*/
|
|
13
|
+
this.schema.createTable('queue_jobs', (table) => {
|
|
14
|
+
table.string('id', 255).notNullable()
|
|
15
|
+
table.string('queue', 255).notNullable()
|
|
16
|
+
table.enum('status', ['pending', 'active', 'delayed']).notNullable()
|
|
17
|
+
table.text('data').notNullable()
|
|
18
|
+
table.bigint('score').unsigned().nullable()
|
|
19
|
+
table.string('worker_id', 255).nullable()
|
|
20
|
+
table.bigint('acquired_at').unsigned().nullable()
|
|
21
|
+
table.bigint('execute_at').unsigned().nullable()
|
|
22
|
+
table.primary(['id', 'queue'])
|
|
23
|
+
table.index(['queue', 'status', 'score'])
|
|
24
|
+
table.index(['queue', 'status', 'execute_at'])
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Schedules table - stores recurring job schedules
|
|
29
|
+
*/
|
|
30
|
+
this.schema.createTable('queue_schedules', (table) => {
|
|
31
|
+
table.string('id', 255).primary()
|
|
32
|
+
table.string('status', 50).notNullable().defaultTo('active')
|
|
33
|
+
table.string('job_name', 255).notNullable()
|
|
34
|
+
table.text('payload').notNullable()
|
|
35
|
+
table.string('cron_expression', 255).nullable()
|
|
36
|
+
table.bigint('every_ms').unsigned().nullable()
|
|
37
|
+
table.string('timezone', 100).notNullable().defaultTo('UTC')
|
|
38
|
+
table.timestamp('from_date').nullable()
|
|
39
|
+
table.timestamp('to_date').nullable()
|
|
40
|
+
table.integer('run_limit').unsigned().nullable()
|
|
41
|
+
table.integer('run_count').unsigned().notNullable().defaultTo(0)
|
|
42
|
+
table.timestamp('next_run_at').nullable()
|
|
43
|
+
table.timestamp('last_run_at').nullable()
|
|
44
|
+
table.timestamp('created_at').notNullable()
|
|
45
|
+
table.index(['status', 'next_run_at'])
|
|
46
|
+
})
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
async down() {
|
|
50
|
+
this.schema.dropTable('queue_jobs')
|
|
51
|
+
this.schema.dropTable('queue_schedules')
|
|
52
|
+
}
|
|
53
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,144 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* @adonisjs/queue
|
|
3
|
+
*
|
|
4
|
+
* (c) AdonisJS
|
|
5
|
+
*
|
|
6
|
+
* For the full copyright and license information, please view the LICENSE
|
|
7
|
+
* file that was distributed with this source code.
|
|
8
|
+
*/
|
|
9
|
+
var __rewriteRelativeImportExtension = (this && this.__rewriteRelativeImportExtension) || function (path, preserveJsx) {
|
|
10
|
+
if (typeof path === "string" && /^\.\.?\//.test(path)) {
|
|
11
|
+
return path.replace(/\.(tsx)$|((?:\.d)?)((?:\.[^./]+?)?)\.([cm]?)ts$/i, function (m, tsx, d, ext, cm) {
|
|
12
|
+
return tsx ? preserveJsx ? ".jsx" : ".js" : d && (!ext || !cm) ? m : (d + ext + "." + cm.toLowerCase() + "js");
|
|
13
|
+
});
|
|
14
|
+
}
|
|
15
|
+
return path;
|
|
16
|
+
};
|
|
17
|
+
import { test } from '@japa/runner';
|
|
18
|
+
import { fileURLToPath } from 'node:url';
|
|
19
|
+
import { IgnitorFactory } from '@adonisjs/core/factories';
|
|
20
|
+
import Configure from '@adonisjs/core/commands/configure';
|
|
21
|
+
const BASE_URL = new URL('./tmp/', import.meta.url);
|
|
22
|
+
test.group('Configure', (group) => {
|
|
23
|
+
group.tap((t) => t.timeout(10_000));
|
|
24
|
+
group.each.setup(async ({ context }) => {
|
|
25
|
+
context.fs.baseUrl = BASE_URL;
|
|
26
|
+
context.fs.basePath = fileURLToPath(BASE_URL);
|
|
27
|
+
await context.fs.create('.env', '');
|
|
28
|
+
await context.fs.createJson('tsconfig.json', {});
|
|
29
|
+
await context.fs.create('start/env.ts', `export default Env.create(new URL('./'), {})`);
|
|
30
|
+
await context.fs.create('adonisrc.ts', `export default defineConfig({})`);
|
|
31
|
+
});
|
|
32
|
+
test('should register provider and command', async ({ assert }) => {
|
|
33
|
+
const ignitor = new IgnitorFactory()
|
|
34
|
+
.withCoreProviders()
|
|
35
|
+
.withCoreConfig()
|
|
36
|
+
.create(BASE_URL, {
|
|
37
|
+
importer: (filePath) => {
|
|
38
|
+
if (filePath.startsWith('./') || filePath.startsWith('../')) {
|
|
39
|
+
return import(__rewriteRelativeImportExtension(new URL(filePath, BASE_URL).href));
|
|
40
|
+
}
|
|
41
|
+
return import(__rewriteRelativeImportExtension(filePath));
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
const app = ignitor.createApp('web');
|
|
45
|
+
await app.init().then(() => app.boot());
|
|
46
|
+
const ace = await app.container.make('ace');
|
|
47
|
+
ace.prompt.trap('Select the queue driver you plan to use').chooseOption(0);
|
|
48
|
+
ace.ui.switchMode('raw');
|
|
49
|
+
const command = await ace.create(Configure, ['../../index.js']);
|
|
50
|
+
await command.exec();
|
|
51
|
+
await assert.fileExists('adonisrc.ts');
|
|
52
|
+
await assert.fileContains('adonisrc.ts', '@adonisjs/queue/queue_provider');
|
|
53
|
+
await assert.fileContains('adonisrc.ts', '@adonisjs/queue/commands');
|
|
54
|
+
});
|
|
55
|
+
test('should create configuration file', async ({ assert }) => {
|
|
56
|
+
const ignitor = new IgnitorFactory()
|
|
57
|
+
.withCoreProviders()
|
|
58
|
+
.withCoreConfig()
|
|
59
|
+
.create(BASE_URL, {
|
|
60
|
+
importer: (filePath) => {
|
|
61
|
+
if (filePath.startsWith('./') || filePath.startsWith('../')) {
|
|
62
|
+
return import(__rewriteRelativeImportExtension(new URL(filePath, BASE_URL).href));
|
|
63
|
+
}
|
|
64
|
+
return import(__rewriteRelativeImportExtension(filePath));
|
|
65
|
+
},
|
|
66
|
+
});
|
|
67
|
+
const app = ignitor.createApp('web');
|
|
68
|
+
await app.init().then(() => app.boot());
|
|
69
|
+
const ace = await app.container.make('ace');
|
|
70
|
+
ace.prompt.trap('Select the queue driver you plan to use').chooseOption(0);
|
|
71
|
+
ace.ui.switchMode('raw');
|
|
72
|
+
const command = await ace.create(Configure, ['../../index.js']);
|
|
73
|
+
await command.exec();
|
|
74
|
+
await assert.fileExists('config/queue.ts');
|
|
75
|
+
await assert.fileContains('config/queue.ts', 'defineConfig');
|
|
76
|
+
});
|
|
77
|
+
test('should add environment variables', async ({ assert }) => {
|
|
78
|
+
const ignitor = new IgnitorFactory()
|
|
79
|
+
.withCoreProviders()
|
|
80
|
+
.withCoreConfig()
|
|
81
|
+
.create(BASE_URL, {
|
|
82
|
+
importer: (filePath) => {
|
|
83
|
+
if (filePath.startsWith('./') || filePath.startsWith('../')) {
|
|
84
|
+
return import(__rewriteRelativeImportExtension(new URL(filePath, BASE_URL).href));
|
|
85
|
+
}
|
|
86
|
+
return import(__rewriteRelativeImportExtension(filePath));
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
const app = ignitor.createApp('web');
|
|
90
|
+
await app.init().then(() => app.boot());
|
|
91
|
+
const ace = await app.container.make('ace');
|
|
92
|
+
ace.prompt.trap('Select the queue driver you plan to use').chooseOption(0);
|
|
93
|
+
ace.ui.switchMode('raw');
|
|
94
|
+
const command = await ace.create(Configure, ['../../index.js']);
|
|
95
|
+
await command.exec();
|
|
96
|
+
await assert.fileContains('.env', 'QUEUE_DRIVER');
|
|
97
|
+
await assert.fileContains('start/env.ts', 'QUEUE_DRIVER');
|
|
98
|
+
});
|
|
99
|
+
test('should create redis config when redis driver selected', async ({ assert }) => {
|
|
100
|
+
const ignitor = new IgnitorFactory()
|
|
101
|
+
.withCoreProviders()
|
|
102
|
+
.withCoreConfig()
|
|
103
|
+
.create(BASE_URL, {
|
|
104
|
+
importer: (filePath) => {
|
|
105
|
+
if (filePath.startsWith('./') || filePath.startsWith('../')) {
|
|
106
|
+
return import(__rewriteRelativeImportExtension(new URL(filePath, BASE_URL).href));
|
|
107
|
+
}
|
|
108
|
+
return import(__rewriteRelativeImportExtension(filePath));
|
|
109
|
+
},
|
|
110
|
+
});
|
|
111
|
+
const app = ignitor.createApp('web');
|
|
112
|
+
await app.init().then(() => app.boot());
|
|
113
|
+
const ace = await app.container.make('ace');
|
|
114
|
+
ace.prompt.trap('Select the queue driver you plan to use').chooseOption(0); // redis
|
|
115
|
+
ace.ui.switchMode('raw');
|
|
116
|
+
const command = await ace.create(Configure, ['../../index.js']);
|
|
117
|
+
await command.exec();
|
|
118
|
+
await assert.fileContains('config/queue.ts', 'drivers.redis');
|
|
119
|
+
await assert.fileContains('.env', 'QUEUE_DRIVER=redis');
|
|
120
|
+
});
|
|
121
|
+
test('should create database config when database driver selected', async ({ assert }) => {
|
|
122
|
+
const ignitor = new IgnitorFactory()
|
|
123
|
+
.withCoreProviders()
|
|
124
|
+
.withCoreConfig()
|
|
125
|
+
.create(BASE_URL, {
|
|
126
|
+
importer: (filePath) => {
|
|
127
|
+
if (filePath.startsWith('./') || filePath.startsWith('../')) {
|
|
128
|
+
return import(__rewriteRelativeImportExtension(new URL(filePath, BASE_URL).href));
|
|
129
|
+
}
|
|
130
|
+
return import(__rewriteRelativeImportExtension(filePath));
|
|
131
|
+
},
|
|
132
|
+
});
|
|
133
|
+
const app = ignitor.createApp('web');
|
|
134
|
+
await app.init().then(() => app.boot());
|
|
135
|
+
const ace = await app.container.make('ace');
|
|
136
|
+
ace.prompt.trap('Select the queue driver you plan to use').chooseOption(1); // database
|
|
137
|
+
ace.prompt.trap('Do you want to publish the migration for the queue tables?').reject();
|
|
138
|
+
ace.ui.switchMode('raw');
|
|
139
|
+
const command = await ace.create(Configure, ['../../index.js']);
|
|
140
|
+
await command.exec();
|
|
141
|
+
await assert.fileContains('config/queue.ts', 'drivers.database');
|
|
142
|
+
await assert.fileContains('.env', 'QUEUE_DRIVER=database');
|
|
143
|
+
});
|
|
144
|
+
});
|
package/package.json
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@adonisjs/queue",
|
|
3
|
+
"description": "Queue system for AdonisJS powered by @boringnode/queue",
|
|
4
|
+
"version": "0.1.1",
|
|
5
|
+
"engines": {
|
|
6
|
+
"node": ">=20.11.1"
|
|
7
|
+
},
|
|
8
|
+
"main": "build/index.js",
|
|
9
|
+
"type": "module",
|
|
10
|
+
"files": [
|
|
11
|
+
"build"
|
|
12
|
+
],
|
|
13
|
+
"exports": {
|
|
14
|
+
".": "./build/index.js",
|
|
15
|
+
"./queue_provider": "./build/providers/queue_provider.js",
|
|
16
|
+
"./commands/*": "./build/commands/*.js",
|
|
17
|
+
"./commands": "./build/commands/main.js",
|
|
18
|
+
"./services/main": "./build/services/queue.js",
|
|
19
|
+
"./types": "./build/src/types/main.js"
|
|
20
|
+
},
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "npm run compile",
|
|
23
|
+
"clean": "del-cli build",
|
|
24
|
+
"compile": "npm run clean && tsc",
|
|
25
|
+
"copy:templates": "copyfiles \"stubs/**/*.stub\" build",
|
|
26
|
+
"index:commands": "adonis-kit index build/commands",
|
|
27
|
+
"format": "prettier --write .",
|
|
28
|
+
"lint": "eslint .",
|
|
29
|
+
"postcompile": "npm run copy:templates && npm run index:commands",
|
|
30
|
+
"prepublishOnly": "npm run build",
|
|
31
|
+
"quick:test": "node --enable-source-maps --import=@poppinss/ts-exec bin/test.ts",
|
|
32
|
+
"test": "c8 npm run quick:test",
|
|
33
|
+
"release": "release-it",
|
|
34
|
+
"typecheck": "tsc --noEmit",
|
|
35
|
+
"version": "npm run build"
|
|
36
|
+
},
|
|
37
|
+
"dependencies": {
|
|
38
|
+
"@boringnode/queue": "^0.1.0",
|
|
39
|
+
"@poppinss/utils": "^6.10.1"
|
|
40
|
+
},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@adonisjs/assembler": "^7.8.2",
|
|
43
|
+
"@adonisjs/core": "^6.17.2",
|
|
44
|
+
"@adonisjs/eslint-config": "^2.0.0",
|
|
45
|
+
"@adonisjs/lucid": "^21.7.0",
|
|
46
|
+
"@adonisjs/prettier-config": "^1.4.4",
|
|
47
|
+
"@adonisjs/redis": "^9.2.0",
|
|
48
|
+
"@adonisjs/tsconfig": "^1.4.0",
|
|
49
|
+
"@japa/assert": "^4.0.1",
|
|
50
|
+
"@japa/file-system": "^2.3.2",
|
|
51
|
+
"@japa/runner": "^4.2.0",
|
|
52
|
+
"@poppinss/ts-exec": "^1.4.1",
|
|
53
|
+
"@release-it/conventional-changelog": "^10.0.4",
|
|
54
|
+
"@types/node": "^20.17.22",
|
|
55
|
+
"c8": "^10.1.3",
|
|
56
|
+
"copyfiles": "^2.4.1",
|
|
57
|
+
"del-cli": "^6.0.0",
|
|
58
|
+
"eslint": "^9.23.0",
|
|
59
|
+
"prettier": "^3.5.3",
|
|
60
|
+
"release-it": "^19.2.2",
|
|
61
|
+
"typescript": "^5.8.2"
|
|
62
|
+
},
|
|
63
|
+
"peerDependencies": {
|
|
64
|
+
"@adonisjs/assembler": "^7.0.0 || ^8.0.0",
|
|
65
|
+
"@adonisjs/core": "^6.2.0 || ^7.0.0",
|
|
66
|
+
"@adonisjs/lucid": "^20.0.0 || ^21.0.0 || ^22.0.0",
|
|
67
|
+
"@adonisjs/redis": "^8.0.0 || ^9.0.0 || ^10.0.0"
|
|
68
|
+
},
|
|
69
|
+
"peerDependenciesMeta": {
|
|
70
|
+
"@adonisjs/lucid": {
|
|
71
|
+
"optional": true
|
|
72
|
+
},
|
|
73
|
+
"@adonisjs/redis": {
|
|
74
|
+
"optional": true
|
|
75
|
+
}
|
|
76
|
+
},
|
|
77
|
+
"author": "Romain Lanz <romain.lanz@pm.me>",
|
|
78
|
+
"license": "MIT",
|
|
79
|
+
"keywords": [
|
|
80
|
+
"queue",
|
|
81
|
+
"jobs",
|
|
82
|
+
"background-jobs",
|
|
83
|
+
"adonisjs",
|
|
84
|
+
"adonis"
|
|
85
|
+
],
|
|
86
|
+
"prettier": "@adonisjs/prettier-config",
|
|
87
|
+
"publishConfig": {
|
|
88
|
+
"access": "public",
|
|
89
|
+
"tag": "latest"
|
|
90
|
+
},
|
|
91
|
+
"release-it": {
|
|
92
|
+
"git": {
|
|
93
|
+
"requireCleanWorkingDir": true,
|
|
94
|
+
"requireUpstream": true,
|
|
95
|
+
"commitMessage": "chore(release): ${version}",
|
|
96
|
+
"tagAnnotation": "v${version}",
|
|
97
|
+
"push": true,
|
|
98
|
+
"tagName": "v${version}"
|
|
99
|
+
},
|
|
100
|
+
"github": {
|
|
101
|
+
"release": true
|
|
102
|
+
},
|
|
103
|
+
"npm": {
|
|
104
|
+
"publish": true,
|
|
105
|
+
"skipChecks": true
|
|
106
|
+
},
|
|
107
|
+
"plugins": {
|
|
108
|
+
"@release-it/conventional-changelog": {
|
|
109
|
+
"preset": {
|
|
110
|
+
"name": "angular"
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
"c8": {
|
|
116
|
+
"reporter": [
|
|
117
|
+
"text",
|
|
118
|
+
"html"
|
|
119
|
+
],
|
|
120
|
+
"exclude": [
|
|
121
|
+
"tests/**"
|
|
122
|
+
]
|
|
123
|
+
}
|
|
124
|
+
}
|