felixmosh / bull-board

🎯 Queue background jobs inspector
MIT License
2.14k stars 343 forks source link

Job details won't show up in express 5.x #738

Closed itsTeknas closed 1 month ago

itsTeknas commented 1 month ago

Job Details are not showing up

Screenshot 2024-05-09 at 10 40 10 AM

The list of jobs is working fine

Screenshot 2024-05-09 at 10 40 16 AM

The actual queue is functioning well also.

My Implementation

import { createBullBoard } from '@bull-board/api'
import { BullMQAdapter } from '@bull-board/api/bullMQAdapter'
import { ExpressAdapter } from '@bull-board/express'

import { EmailQueue, PriorityEmailQueue } from '../queues/emailQueue'

const BullMQStatus = new ExpressAdapter()
BullMQStatus.setBasePath('/bullmq')

export const app = express()

app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use(express.static(path.join(__dirname, 'public')))
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'hbs')

createBullBoard({
  queues: [
    new BullMQAdapter(EmailQueue, {readOnlyMode: true}),
    new BullMQAdapter(PriorityEmailQueue, {readOnlyMode: true}),
  ],
  serverAdapter: BullMQStatus,
})
app.use('/bullmq', BullMQStatus.getRouter())

Dependencies:

"@bull-board/api": "^5.17.1"
"@bull-board/express": "^5.17.1"
"bullmq": "^5.7.5"

Redis

Screenshot 2024-05-09 at 10 45 59 AM

Queue Definition

import { Queue, Worker } from 'bullmq'

export const PriorityEmailQueue = new Queue<Email>(
  'priority-email-queue',
  {
    connection: redis.duplicate(),
    defaultJobOptions: {
      removeOnComplete: {
        count: 500,
      },
      removeOnFail: {
        count: 500,
      },
    },
  },
)

I'm not sure if my implementation is wrong or if this is a bug.

felixmosh commented 1 month ago

What lib do you use? Bull or BullMQ?

itsTeknas commented 1 month ago

@felixmosh BullMQ "bullmq": "^5.7.5"

felixmosh commented 1 month ago

Ok, your setup looks OK. Try to check the "latest" tab, or any other. Can I debug it somehow?

itsTeknas commented 1 month ago

Checking the Latest Tab with inspect element,

Screenshot 2024-05-09 at 11 37 20 AM

{
    "queues": [
        {
            "name": "email-queue",
            "statuses": [
                "latest",
                "active",
                "waiting",
                "waiting-children",
                "prioritized",
                "completed",
                "failed",
                "delayed",
                "paused"
            ],
            "counts": {
                "active": 0,
                "completed": 0,
                "delayed": 0,
                "failed": 0,
                "paused": 0,
                "prioritized": 0,
                "waiting": 0,
                "waiting-children": 0
            },
            "jobs": [],
            "pagination": {
                "pageCount": 1,
                "range": {
                    "start": 0,
                    "end": 9
                }
            },
            "readOnlyMode": true,
            "allowRetries": false,
            "allowCompletedRetries": false,
            "isPaused": false
        },
        {
            "name": "priority-email-queue",
            "statuses": [
                "latest",
                "active",
                "waiting",
                "waiting-children",
                "prioritized",
                "completed",
                "failed",
                "delayed",
                "paused"
            ],
            "counts": {
                "active": 0,
                "completed": 2,
                "delayed": 0,
                "failed": 0,
                "paused": 0,
                "prioritized": 0,
                "waiting": 0,
                "waiting-children": 0
            },
            "jobs": [],
            "pagination": {
                "pageCount": 1,
                "range": {
                    "start": 0,
                    "end": 9
                }
            },
            "readOnlyMode": true,
            "allowRetries": false,
            "allowCompletedRetries": false,
            "isPaused": false
        },
        ...
    ]
}

The URL is public without any auth, you can check right now

https://api.core.hedged.online/bullmq

itsTeknas commented 1 month ago

@felixmosh I have a gut feeling that the query parameters may not be parsing. The response looks the same for the homepage /bullmq/api/queues?page=1&jobsPerPage=10

I'm using "express": "5.0.0-beta.3"

Middleware stack

app.use(express.json())
app.use(express.urlencoded({ extended: true }))
app.use(express.static(path.join(__dirname, 'public')))
app.set('views', path.join(__dirname, 'views'))
app.set('view engine', 'hbs')
felixmosh commented 1 month ago

Ha, ofcourse, we don't support express 5 yet, can you try to downgrade it to v4?

itsTeknas commented 1 month ago

Yes, that worked! But i really use some important express 5 features in my app like async (req,res) with throw error in the middle and a global catcher.

I'm afraid, I can't downgrade my project.

Is there any guidance on making it compatible with express 5 ? Or a quick fix by adding some middleware etc ?

felixmosh commented 1 month ago

You were right, express 5 probably not parsing query string properly, just add a console.log in side the queue handler, and check what are the params that you get.

itsTeknas commented 1 month ago

so i did this in express 5.x ,

router.use('/bullmq', (req,res,next) => {
  console.log(req.query)
  next()
})
router.use('/bullmq', BullMQStatus.getRouter())

And Got

[Object: null prototype] {
  activeQueue: 'priority-email-queue',
  status: 'latest',
  page: '1',
  jobsPerPage: '10'
}

when using app.set('query parser', 'simple')

And

 {
  activeQueue: 'priority-email-queue',
  status: 'latest',
  page: '1',
  jobsPerPage: '10'
}

when using app.set('query parser', 'extended')

Neither of them showed the job details, As a side-node the rest of my app uses query strings and I never had a problem.

felixmosh commented 1 month ago

duplicate of #404

itsTeknas commented 1 month ago

For future readers, The current workaround is adding a middleware before the express adapter.

// BullBoard Currently does not support express 5, so we need to manually set the query as a property on req
router.use('/bullmq', (req: Request, res: Response, next: NextFunction) => {
  const query = req.query;
  // Set query as a property on req instead of as a getter for backward
  // compatibility with express 4
  Object.defineProperty(req, 'query', { get: () => query });
  next();
});
router.use('/bullmq', BullMQStatus.getRouter());