Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
35 changes: 34 additions & 1 deletion .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,9 @@ on:
- pull_request
- workflow_call

permissions:
contents: read

jobs:
lint:
uses: adonisjs/.github/.github/workflows/lint.yml@main
Expand All @@ -13,4 +16,34 @@ jobs:
uses: adonisjs/.github/.github/workflows/typecheck.yml@main

tests:
uses: adonisjs/.github/.github/workflows/test.yml@main
runs-on: ubuntu-latest
env:
REDIS_HOST: 127.0.0.1
REDIS_PORT: 6379
strategy:
matrix:
node-version: ['lts/krypton', 'latest']
services:
redis:
image: redis
options: >-
--health-cmd "redis-cli ping"
--health-interval 10s
--health-timeout 5s
--health-retries 5
ports:
- 6379:6379
steps:
- name: Checkout code
uses: actions/checkout@v4

- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}

- name: Install dependencies
run: npm install

- name: Run tests
run: npm test
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
12 changes: 6 additions & 6 deletions .github/workflows/stale.yml
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
name: "Close stale issues and PRs"
name: 'Close stale issues and PRs'
on:
schedule:
- cron: "30 0 * * *"
- cron: '30 0 * * *'

jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
with:
stale-issue-message: "This issue has been marked as stale because it has been inactive for more than 21 days. Please reopen if you still need help on this issue"
stale-pr-message: "This pull request has been marked as stale because it has been inactive for more than 21 days. Please reopen if you still intend to submit this pull request"
close-issue-message: "This issue has been automatically closed because it has been inactive for more than 4 weeks. Please reopen if you still need help on this issue"
close-pr-message: "This pull request has been automatically closed because it has been inactive for more than 4 weeks. Please reopen if you still intend to submit this pull request"
stale-issue-message: 'This issue has been marked as stale because it has been inactive for more than 21 days. Please reopen if you still need help on this issue'
stale-pr-message: 'This pull request has been marked as stale because it has been inactive for more than 21 days. Please reopen if you still intend to submit this pull request'
close-issue-message: 'This issue has been automatically closed because it has been inactive for more than 4 weeks. Please reopen if you still need help on this issue'
close-pr-message: 'This pull request has been automatically closed because it has been inactive for more than 4 weeks. Please reopen if you still intend to submit this pull request'
days-before-stale: 21
days-before-close: 5
25 changes: 13 additions & 12 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,30 +36,31 @@
"version": "npm run build"
},
"dependencies": {
"@boringnode/queue": "^0.6.0"
"@boringnode/queue": "^0.7.1"
},
"devDependencies": {
"@adonisjs/assembler": "^8.4.0",
"@adonisjs/core": "^7.3.4",
"@adonisjs/assembler": "^8.5.0",
"@adonisjs/core": "^7.5.0",
"@adonisjs/eslint-config": "^3.1.0",
"@adonisjs/lucid": "^22.4.2",
"@adonisjs/prettier-config": "^1.5.0",
"@adonisjs/redis": "^10.0.0",
"@adonisjs/redis": "^10.0.1",
"@adonisjs/tsconfig": "^2.0.0",
"@japa/assert": "^4.2.0",
"@japa/file-system": "^3.0.0",
"@japa/runner": "^5.3.0",
"@poppinss/ts-exec": "^1.4.4",
"@release-it/conventional-changelog": "^11.0.1",
"@types/node": "~24.11.2",
"c8": "^11.0.0",
"@release-it/conventional-changelog": "^12.0.0",
"@types/node": "~26.3.0",
"better-sqlite3": "^13.0.3",
"c8": "^12.0.0",
"cpy-cli": "^7.0.0",
"del-cli": "^7.0.0",
"eslint": "^9.39.4",
"kysely": "^0.29.3",
"prettier": "^3.9.1",
"release-it": "^20.2.1",
"typescript": "^5.9.3"
"eslint": "^10.9.1",
"kysely": "^0.29.5",
"prettier": "^3.9.6",
"release-it": "^21.0.2",
"typescript": "^6.0.3"
},
"peerDependencies": {
"@adonisjs/assembler": "^8.0.0",
Expand Down
8 changes: 7 additions & 1 deletion providers/queue_provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,13 @@ export default class QueueProvider {
}

async start() {
if (this.app.getEnvironment() === 'console') {
/**
* Nothing dispatches or processes jobs in the console environment or in
* an app warming up, since a warmed up app never becomes ready. The
* "getMode" method is missing in the older versions of the framework core
* without the "warmup" mode.
*/
if (this.app.getEnvironment() === 'console' || this.app.getMode?.() === 'warmup') {
return
}

Expand Down
24 changes: 20 additions & 4 deletions src/drivers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,8 +58,18 @@ export const drivers: {
const redis = await app.container.make('redis')
const { redis: redisAdapter } = await import('@boringnode/queue/drivers/redis_adapter')

const connection = redis.connection(config?.connectionName)
return redisAdapter((connection as any).ioConnection)
/**
* The connection is acquired from within the factory and not when the
* config provider is resolved. The queue manager resolves every adapter
* when the app starts, whereas it invokes the factory only when the
* adapter is used for the first time. Acquiring the connection eagerly
* would open a socket during the app start, even when nothing ever
* touches the queue
*/
return () => {
const connection = redis.connection(config?.connectionName)
return redisAdapter((connection as any).ioConnection)()
}
})
},

Expand All @@ -69,9 +79,15 @@ export const drivers: {
const { knex } = await import('@boringnode/queue/drivers/knex_adapter')

const connectionName = config?.connectionName || db.primaryConnectionName
const connection = db.connection(connectionName)

return knex(connection.getWriteClient(), config?.tableName)
/**
* Same as the redis driver. The connection is acquired when the adapter
* is used for the first time and not when the app starts
*/
return () => {
const connection = db.connection(connectionName)
return knex(connection.getWriteClient(), config?.tableName)()
}
})
},

Expand Down
119 changes: 119 additions & 0 deletions tests/drivers/database.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/*
* @adonisjs/queue
*
* (c) AdonisJS
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/

import { test } from '@japa/runner'

import { defineConfig, drivers } from '../../index.js'
import { resolveAdapters } from '../../src/utils.js'
import { getDatabaseConfig, setupApp } from '../helpers.js'
import type { QueueConfig } from '../../src/types/main.js'

const databaseProvider = () => import('@adonisjs/lucid/database_provider')

test.group('drivers | database', () => {
test('do not acquire a connection when resolving the adapter', async ({ assert }) => {
const app = await setupApp(
'console',
{
database: getDatabaseConfig(),
queue: defineConfig({
default: 'database',
adapters: {
database: drivers.database({ connectionName: 'jobs' }),
},
}),
},
[databaseProvider]
)

const db = await app.container.make('lucid.db')
const config = app.config.get<QueueConfig>('queue')
const resolvedAdapters = await resolveAdapters(config, app)

assert.isFunction(resolvedAdapters.database)
assert.isFalse(db.manager.isConnected('jobs'))
assert.isFalse(db.manager.isConnected('main'))
})

test('acquire the configured connection when creating the adapter', async ({ assert }) => {
const app = await setupApp(
'console',
{
database: getDatabaseConfig(),
queue: defineConfig({
default: 'database',
adapters: {
database: drivers.database({ connectionName: 'jobs' }),
},
}),
},
[databaseProvider]
)

const db = await app.container.make('lucid.db')
const config = app.config.get<QueueConfig>('queue')
const resolvedAdapters = await resolveAdapters(config, app)

resolvedAdapters.database()
assert.isTrue(db.manager.isConnected('jobs'))
assert.isFalse(db.manager.isConnected('main'))
})

test('use the primary connection when no connection name is configured', async ({ assert }) => {
const app = await setupApp(
'console',
{
database: getDatabaseConfig(),
queue: defineConfig({
default: 'database',
adapters: {
database: drivers.database(),
},
}),
},
[databaseProvider]
)

const db = await app.container.make('lucid.db')
const config = app.config.get<QueueConfig>('queue')
const resolvedAdapters = await resolveAdapters(config, app)

resolvedAdapters.database()
assert.isTrue(db.manager.isConnected('main'))
assert.isFalse(db.manager.isConnected('jobs'))
})

test('do not acquire a connection when the app starts', async ({ assert }) => {
const app = await setupApp(
'web',
{
database: getDatabaseConfig(),
queue: defineConfig({
default: 'database',
adapters: {
database: drivers.database(),
},
}),
},
[databaseProvider]
)

/**
* Starting the app in the "web" environment initializes the queue
* manager from the provider's start hook. Doing so must not open any
* connection, since nothing releases them in a process that never
* becomes ready (for example, the "codegen" command)
*/
await app.start(() => {})

const db = await app.container.make('lucid.db')
assert.isFalse(db.manager.isConnected('main'))
assert.isFalse(db.manager.isConnected('jobs'))
})
})
Loading
Loading