Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Migrate to adonis 5 #39

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
2620be1
feat: migrate provider to adonis 5
RodolfoSilva Sep 6, 2020
8b2e1a0
fix: provider factory
RodolfoSilva Sep 6, 2020
cd3e1ff
feat: add index.ts to set typescript reference
RodolfoSilva Sep 6, 2020
ab15a3f
fix: redis types
RodolfoSilva Sep 6, 2020
17d24e3
fix: test - Bull: should add a new job
RodolfoSilva Sep 6, 2020
32ea216
fix: test - Bull: should add a new job with events inside Job class
RodolfoSilva Sep 6, 2020
bb8f3d1
fix: test - Bull: should schedule a new job
RodolfoSilva Sep 6, 2020
188947e
fix: test - Bull: shouldn't schedule when time is invalid
RodolfoSilva Sep 6, 2020
7469512
fix: test - Provider: BullProvider
RodolfoSilva Sep 6, 2020
020b08d
feat: update documentation
RodolfoSilva Sep 7, 2020
c67e33b
feat: add commands
RodolfoSilva Sep 7, 2020
82aa20c
chore: update dependencies
RodolfoSilva Sep 7, 2020
f2baeba
feat: rollback property queueName to key
RodolfoSilva Sep 7, 2020
0621e2b
feat: update error handler documentation
RodolfoSilva Sep 7, 2020
aaf1610
feat: migrate bull:listen command to adonis 5
RodolfoSilva Sep 7, 2020
8358d3f
chore: remove config.json
RodolfoSilva Sep 7, 2020
418ffde
feat: add test coverage script
RodolfoSilva Sep 7, 2020
837e1f7
feat: wrap the test execution with nyc
RodolfoSilva Sep 7, 2020
33261de
feat: convert tab to space
RodolfoSilva Sep 7, 2020
17d4d59
feat: update ignore and replace package-lock with yarn.lcok
RodolfoSilva Sep 7, 2020
a3b58d7
feat: format config files and reorder package.json
RodolfoSilva Sep 7, 2020
02a3be6
feat: update handle type
RodolfoSilva Sep 7, 2020
a7cbb72
feat: registry Listen command
RodolfoSilva Sep 7, 2020
28bf2a6
feat: remove empty methods
RodolfoSilva Sep 7, 2020
31c9e4e
feat: convert js class to ts
RodolfoSilva Sep 7, 2020
8f54085
fix: typo in the documentation
RodolfoSilva Sep 7, 2020
4c642fd
feat: add test case
RodolfoSilva Sep 7, 2020
d00e003
feat: restore previous .eslintrc.js adding the typescript configuration
RodolfoSilva Sep 7, 2020
f75d003
feat: fix lint warnings
RodolfoSilva Sep 7, 2020
4dfd3d5
feat: remove .editorconfig
RodolfoSilva Sep 7, 2020
3e04ebd
feat: remove .npmignore
RodolfoSilva Sep 7, 2020
2ab5d32
feat: remove prettier stuf
RodolfoSilva Sep 7, 2020
b34f688
feat: remove docker files
RodolfoSilva Sep 7, 2020
ee4b964
feat: remove .eslintignore
RodolfoSilva Sep 7, 2020
9750e6d
feat: remove some packages and scripts from package.json
RodolfoSilva Sep 7, 2020
1302e98
feat: update docs with redis configuration and auto export all jobs s…
RodolfoSilva Sep 7, 2020
dcf2c8d
feat: remove dist
RodolfoSilva Sep 7, 2020
7ddd439
feat: add script to auto export all jobs
RodolfoSilva Sep 7, 2020
eaaaecd
refactor: remove @adonisjs/redis, should use the redis provided by bull
RodolfoSilva Nov 27, 2020
fefac47
feat: ignore IDE config files
RodolfoSilva Nov 27, 2020
1685fe4
chore: update documentation
RodolfoSilva Nov 27, 2020
0a68642
feat: add exception handler
RodolfoSilva Dec 5, 2020
5f6e365
feat: add test case to BullExceptionHandler
RodolfoSilva Dec 6, 2020
910e60c
Merge branch 'master' into feature/migrate-to-adonis-5
RodolfoSilva Jan 19, 2021
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
module.exports = {
parser: '@typescript-eslint/parser',
env: {
es6: true,
node: true
node: true,
},
extends: [
'standard'
],
extends: ['standard'],
globals: {
Atomics: 'readonly',
SharedArrayBuffer: 'readonly'
SharedArrayBuffer: 'readonly',
},
parserOptions: {
ecmaVersion: 2018
ecmaVersion: 2018,
},
rules: {
}
'no-useless-constructor': 'off',
},
}
9 changes: 8 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,11 @@ test/tmp
test/database


# End of https://www.gitignore.io/api/node
# End of https://www.gitignore.io/api/node

# builds
build

# IDE
.idea
.vscode
240 changes: 138 additions & 102 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,94 +9,117 @@

## Install

`adonis install @rocketseat/adonis-bull`
YARN

## Use
Register the Bull commands at `start/app.js`
```js
const aceProviders = [
'@rocketseat/adonis-bull/providers/Command',
];
```
yarn add @rocketseat/adonis-bull
```

Register the Bull provider at `start/app.js`
NPM

```js
const providers = [
//...
"@rocketseat/adonis-bull/providers/Bull"
];
```
npm install @rocketseat/adonis-bull
```

Create a file with the `jobs` that will be processed at `start/jobs.js`:
## Use

```js
module.exports = ["App/Jobs/UserRegisterEmail"];
```
Add the config file at `config/bull.ts`:

Add the config file at `config/bull.js`:
```ts
import Env from '@ioc:Adonis/Core/Env'
import { BullConfig } from '@ioc:Rocketseat/Bull'

```js
"use strict";

const Env = use("Env");
const bullConfig: BullConfig = {
connection: Env.get('BULL_CONNECTION'),

module.exports = {
// redis connection
connection: Env.get("BULL_CONNECTION", "bull"),
bull: {
redis: {
host: "127.0.0.1",
port: 6379,
password: null,
db: 0,
keyPrefix: ""
}
host: Env.get('BULL_REDIS_HOST'),
port: Env.get('BULL_REDIS_PORT'),
password: Env.get('BULL_REDIS_PASSWORD', ''),
db: 0,
keyPrefix: '',
},
remote: "redis://redis.example.com?password=correcthorsebatterystaple"
};
}

export default bullConfig
```

In the above file you can define redis connections, there you can pass all `Bull` queue configurations described [here](https://github.com/OptimalBits/bull/blob/develop/REFERENCE.md#queue).

Create a file to initiate `Bull` at `preloads/bull.js`:

```js
const Bull = use("Rocketseat/Bull");
Create a file with the `jobs` that will be processed at `start/jobs.ts`:

Bull.process()
// Optionally you can start BullBoard:
.ui(9999); // http://localhost:9999
// You don't need to specify the port, the default number is 9999
```ts
const jobs = ["App/Jobs/UserRegisterEmail"]

export default jobs
```

Add .preLoad in server.js to initialize the bull preload
Or use the magic way, it will declare all jobs for you:

```ts
import { listDirectoryFiles } from '@adonisjs/ace'
import Application from '@ioc:Adonis/Core/Application'
import { join } from 'path'

/*
|--------------------------------------------------------------------------
| Exporting an array of jobs
|--------------------------------------------------------------------------
|
| Instead of manually exporting each file from the app/Jobs directory, we
| use the helper `listDirectoryFiles` to recursively collect and export
| an array of filenames.
*/
const jobs = listDirectoryFiles(
join(Application.appRoot, 'app/Jobs'),
Application.appRoot
).map((name) => {
return name
.replace(/^\.\/app\/Jobs\//, 'App/Jobs/')
.replace(/\.(?:t|j)s$/, '')
})

export default jobs
```


Create a new preload file by executing the following ace command.

```bash
node ace make:prldfile bull

# ✔ create start/bull.ts
```

```ts
import Bull from '@ioc:Rocketseat/Bull'

```js
new Ignitor(require('@adonisjs/fold'))
.appRoot(__dirname)
.preLoad('preloads/bull') // Add This Line
.fireHttpServer()
.catch(console.error)
Bull.process()
// Optionally you can start BullBoard:
.ui(9999); // http://localhost:9999
// You don't need to specify the port, the default number is 9999
```

## Creating your job

Create a class that mandatorily has the methods `key` and `handle`.
Create a new job file by executing the following ace command.

The `key` method is the unique identification of each job. It has to be a `static get` method.
```bash
node ace make:job userRegisterEmail

The `handle` is the method that contains the functionality of your `job`.
# ✔ create app/Jobs/UserRegisterEmail.ts
```

```js
const Mail = use("Mail");
```ts
import { JobContract } from '@ioc:Rocketseat/Bull'
import Mail from '@ioc:Adonis/Addons/Mail'

class UserRegisterEmail {
static get key() {
return "UserRegisterEmail-key";
}
export default class UserRegisterEmail implements JobContract {
public key = 'UserRegisterEmail'

async handle(job) {
public async handle(job) {
const { data } = job; // the 'data' variable has user data

await Mail.send("emails.welcome", data, message => {
Expand All @@ -109,40 +132,44 @@ class UserRegisterEmail {
return data;
}
}

module.exports = UserRegisterEmail;
```

You can use the `connection` static get method to specify which connection your `job` will work.
You can override the default `configs`.

```js
class UserRegisterEmail {
// ...
static get connection() {
return "remote";
}
```ts
...
import { JobsOptions, QueueOptions, WorkerOptions, Job } from 'bullmq'

export default class UserRegisterEmail implements JobContract {
...
public options: JobsOptions = {}

public queueOptions: QueueOptions = {}

public workerOptions: WorkerOptions = {}
}
```

### Events

You can config the events related to the `job` to have more control over it

```js
const Ws = use('Ws')
```ts
...
import Ws from 'App/Services/Ws'

class UserRegisterEmail {
export default class UserRegisterEmail implements JobContract {
...

onCompleted(job, result) {
Ws
.getChannel('admin:notifications')
.topic('admin:notifications')
.broadcast('new:user', result)
boot(queue) {
queue.on('complete', (job, result) => {
Ws
.getChannel('admin:notifications')
.topic('admin:notifications')
.broadcast('new:user', result)
})
}
}

module.exports = UserRegisterEmail;
```

## Processing the jobs
Expand All @@ -151,12 +178,12 @@ module.exports = UserRegisterEmail;

You can share the `job` of any `controller`, `hook` or any other place you might like:

```js
const User = use('App/Models/User')
const Bull = use('Rocketseat/Bull')
const Job = use('App/Jobs/UserRegisterEmail')
```ts
import User from 'App/Models/User'
import Bull from '@ioc:Rocketseat/Bull'
import Job from 'App/Jobs/UserRegisterEmail'

class UserController {
export default class UserController {
store ({ request, response }) {
const data = request.only(['email', 'name', 'password'])

Expand All @@ -166,31 +193,28 @@ class UserController {
Bull.add(Job.key, user)
}
}

module.exports = UserController
```

### Scheduled job

Sometimes it is necessary to schedule a job instead of shooting it imediately. You should use `schedule` for that:

```js
const User = use('App/Models/User')
const Bull = use('Rocketseat/Bull')
const Job = use('App/Jobs/HolidayOnSaleEmail')
```ts
import User from 'App/Models/User'
import ProductOnSale from 'App/Services/ProductOnSale'
import Bull from '@ioc:Rocketseat/Bull'
import Job from 'App/Jobs/UserRegisterEmail'
import parseISO from 'date-fns/parseISO'

class HolidayOnSaleController {
export default class HolidayOnSaleController {
store ({ request, response }) {
const data = request.only(['date', 'product_list']) // 2019-11-15 12:00:00
const data = request.only(['date', 'product_list']) // 2020-11-06T12:00:00

const products = await ProductOnSale.create(data)


Bull.schedule(Job.key, products, data.date)
Bull.schedule(Job.key, products, parseISO(data.date))
}
}

module.exports = HolidayOnSaleController
```

This `job` will be sent only on the specific date, wich for example here is on November 15th at noon.
Expand All @@ -199,17 +223,24 @@ When finishing a date, never use past dates because it will cause an error.

other ways of using `schedule`:

```js
```ts
Bull.schedule(key, data, new Date("2019-11-15 12:00:00"));
Bull.schedule(key, data, "2 hours"); // 2 hours from now
Bull.schedule(key, data, 60 * 1000); // 1 minute from now.
```

Or with a third party lib:

```ts
import humanInterval from 'human-interval'

Bull.schedule(key, data, humanInterval("2 hours")); // 2 hours from now
```

### Advanced jobs

You can use the own `Bull` configs to improve your job:

```js
```ts
Bull.add(key, data, {
repeat: {
cron: "0 30 12 * * WED,FRI"
Expand All @@ -221,12 +252,19 @@ This `job` will be run at 12:30 PM, only on wednesdays and fridays.

### Exceptions

To have a bigger control over errors that might occur on the line, the events that fail can be manipulated at the file `App/Exceptions/QueueHandler.js`:
To have a bigger control over errors that might occur on the line, the events that fail can be manipulated at the file `app/Exceptions/Handler.ts`:

```ts
import Sentry from 'App/Services/Sentry'

```js
const Sentry = use("Sentry");
import Logger from '@ioc:Adonis/Core/Logger'
import HttpExceptionHandler from '@ioc:Adonis/Core/HttpExceptionHandler'

export default class ExceptionHandler extends HttpExceptionHandler {
constructor () {
super(Logger)
}

class QueueHandler {
async report(error, job) {
Sentry.configureScope(scope => {
scope.setExtra(job);
Expand All @@ -235,6 +273,4 @@ class QueueHandler {
Sentry.captureException(error);
}
}

module.exports = QueueHandler;
```
Loading