felixmosh / bull-board

🎯 Queue background jobs inspector
MIT License
2.31k stars 362 forks source link

Queue is not dynamically updated #368

Closed PengWeibin-Mars closed 2 years ago

PengWeibin-Mars commented 2 years ago

image If my Queue is a dynamic list, it will not be updated, any good suggestions?

PengWeibin-Mars commented 2 years ago

@felixmosh The problem with this list refresh do you have a good opinion?

felixmosh commented 2 years ago

It gets updated automatically, if you are using the given api, it should add / remove the "watched" queues.

Can you share some code?

PengWeibin-Mars commented 2 years ago
const express = require('express');
const { createBullBoard } = require('@bull-board/api');
const { ExpressAdapter } = require('@bull-board/express');
const QueueTool = require('./src/server/queue/queue-tool');
const basicAuth = require('basic-auth');
const { ensureLoggedIn } = require('connect-ensure-login');
const LocalStrategy = require('passport-local').Strategy;
const session = require('express-session');
const bodyParser = require('body-parser');
const passport = require('passport');
var flash = require('connect-flash');

usernameEnv = process.env.USERNAME;
passwordEnv = process.env.PASSWORD;

passport.use(
  new LocalStrategy(function (username, password, cb) {
    if (username === usernameEnv && password === passwordEnv) {
      return cb(null, { user: 'bull-board' });
    }
    return cb(null, false, { message: 'login fail' });
  })
);

passport.serializeUser((user, cb) => {
  cb(null, user);
});

passport.deserializeUser((user, cb) => {
  cb(null, user);
});

const run = async (listenOpts = {}) => {
  const queues = await QueueTool.getQueues('bull:*:id');

  const serverAdapter = new ExpressAdapter();

  createBullBoard({
    queues,
    serverAdapter: serverAdapter,
  });

  const app = express();
  app.use(flash());

  const port = process.env.PORT || 4567;
  const host = listenOpts.host || '0.0.0.0'; // Default: listen to all network interfaces.

  serverAdapter.setBasePath('/ui');

  // Configure view engine to render EJS templates.
  app.set('views', __dirname + '/src/views');
  app.set('view engine', 'ejs');

  app.use(session({ secret: 'keyboard cat', saveUninitialized: true, resave: true }));
  app.use(bodyParser.urlencoded({ extended: false }));

  // // Initialize Passport and restore authentication state, if any, from the session.
  app.use(passport.initialize({}));
  app.use(passport.session({}));

  app.get('/ui/login', (req, res) => {
    res.render('login', { invalid: req.query.invalid === 'true' });
  });

  app.post(
    '/ui/login',
    passport.authenticate('local', { failureRedirect: '/ui/login?invalid=true' }),
    (req, res) => {
      res.redirect('/ui');
    }
  );

  app.use('/add', (req, res) => {
    const opts = req.query.opts || {};

    if (opts.delay) {
      opts.delay = +opts.delay * 1000; // delay must be a number
    }

    exampleBullMq.add('Add', { title: req.query.title }, opts);

    res.json({
      ok: true,
    });
  });

  app.use('/ui', ensureLoggedIn({ redirectTo: '/ui/login' }), serverAdapter.getRouter());
  app.listen(port, host, () => {
    console.log(`Bull-Board is running on port ${port} at hsot ${host}`);
  });

  // return app
};
run().catch((e) => console.error(e));
// if (require.main === module) run();

// module.exports = run;
PengWeibin-Mars commented 2 years ago

Here is the code for index js

felixmosh commented 2 years ago

What is the value of const queues?

PengWeibin-Mars commented 2 years ago

I think here to initialize the Queues List

felixmosh commented 2 years ago

Can you share the code QueueTool.getQueues?

PengWeibin-Mars commented 2 years ago
const Queue = require('bull');
const { BullAdapter } = require('@bull-board/api/bullAdapter');
const RedisClient = require('./redis-client');
const dotenv = require('dotenv');
dotenv.config();
redisUrl = process.env.REDIS_URL;

async function getBullKeys(pattern) {
  const getBullKeys = await RedisClient.redisGetKeys(pattern);
  return getBullKeys;
}

async function getQueueNames(pattern) {
  const bullkey = await getBullKeys(pattern);
  const queueNames = [];
  if (bullkey.length > 0) {
    for (let i = 0; i < bullkey.length; i++) {
      const key = bullkey[i];
      var QueueName = key.split(':');
      queueNames.push(QueueName[1]);
    }
    queueNames.sort();
  }
  console.log(`The currently obtained QueueName collection: ${queueNames}`);
  return queueNames;
}

/**
 * Pass all the queues in the redis server of the queue pattern, and then get the names of all the queues through split
 * @param {bull:*:id} pattern
 * @returns
 */
async function setQueues(pattern) {
  const queueNames = await getQueueNames(pattern);
  const queues = [];
  for (let i = 0; i < queueNames.length; i++) {
    const queue = new Queue(queueNames[i], redisUrl);
    queues.push(new BullAdapter(queue));
  }
  return queues;
}

module.exports = {
  getQueues: setQueues,
};
felixmosh commented 2 years ago

The code looks ok. Do you get an array of your queues when you call to getQueues?

PengWeibin-Mars commented 2 years ago

The getQueues function can normally obtain the Queues data, but currently the list can only be loaded once when the program is initialized. If the Queue data changes subsequently, the new Queue list cannot be obtained in time.

felixmosh commented 2 years ago

This is correct, if you don't have queues when your getQueues is called, Bull-Board won't show them.

There is a solution,

const queueApi =  createBullBoard({
    queues,
    serverAdapter: serverAdapter,
  });

// later in time
queueApi.addQueue(new QueueAdapter(queue));

createBullBoard return a queueApi which allows you to add queues later.

PengWeibin-Mars commented 2 years ago

queueApi.addQueue('queueName', new QueueAdapter); Can I only add a fixed Queue to the current app, and the dynamically added Queue I added dynamically from another app

felixmosh commented 2 years ago

Sorry, it seems that the issue is not related to bull-board.

If you want my help, pls, create a repo with the bug, and i will review it.

I can't help you with your custom setup without it.

ealcantara22 commented 2 years ago

Hello @PengWeibin-Mars, had a similar issue recently, in my case I was handling a massive amount of data inside my job handler which I was returning as the job completion state. Bull-board was trying to display all that data in its returnValue but it was just too much, causing the page to stop working. I resolved by adding specifics job.log where needed and returning a more conservative response.

Sin13 commented 2 years ago

in case anyone is looking for how to use the addQueue method, its not actually like this anymore. you can use it like so:

const queue = new Queue('FOO');
const queueAdaptor = new BullMQAdapter(queue);
addQueue(queueAdaptor);

so you should NOT pass the queueName as the first parameter.

felixmosh commented 2 years ago

in case anyone is looking for how to use the addQueue method, its not actually like this anymore. you can use it like so:

const queue = new Queue('FOO');
const queueAdaptor = new BullMQAdapter(queue);
addQueue(queueAdaptor);

so you should NOT pass the queueName as the first parameter.

Thanx, fixed it