bullmq icon indicating copy to clipboard operation
bullmq copied to clipboard

[Bug]: Cannot read properties of undefined (reading 'forEach')

Open mieradi opened this issue 1 year ago • 7 comments

Version

v4.14.4

Platform

NodeJS

What happened?

In production (hosted on render.com), the job will get added to the queue, but the worker never runs. I am getting en error of Cannot read properties of undefined (reading 'forEach') from my QueueEvents listener. Locally, I have no issue. Been at this for days.

Other info: Node versions are the same, no other errors are being logged, and I can see each job get added to Redis.

How to reproduce.

Not sure if there is a way to reproduce since there seems to be no issue locally, and the issue only happens in production.

Relevant log output

Cannot read properties of undefined (reading 'forEach')

Code of Conduct

  • [X] I agree to follow this project's Code of Conduct

mieradi avatar Dec 02 '23 12:12 mieradi

hi @mieradi do you have any stacktrace of this error?

roggervalf avatar Dec 04 '23 02:12 roggervalf

Besides the callstack it would be useful to see the actual code snippet where the exception is thrown, as it seems like it is coming from user code.

manast avatar Dec 05 '23 10:12 manast

@roggervalf I will work on getting that!

@manast in regards to the code, I have removed all the code in my worker to make sure it works. Right now, it's just a log.

Here is an example

export const remindersQueue = new Queue('event-reminders', {
  connection: {
    host: process.env.REDIS_HOST,
    port: parseInt(process.env.REDIS_PORT as string),
    maxRetriesPerRequest: null,
    enableOfflineQueue: false,
    retryStrategy: function (times: number) {
      return Math.max(Math.min(Math.exp(times), 20000), 1000);
    },
  },
});

export async function handleEventReminders({
  event,
  timezone,
  currentUser,
}: {
  event: EventSchema;
  parent_day_timezone: string;
  currentUser: UserType;
}) {
  // remove job from queue if it exists
  const jobs = await eventRemindersQueue.getDelayed();
  if (jobs) {
    const jobToRemoveIndex = jobs.findIndex(
      (job: any) => job.name === event.event_id
    );

    if (jobToRemoveIndex > -1) {
      jobs[jobToRemoveIndex].remove();
    }
  }

  const currentTime = utcToZonedTime(
    new Date(),
    parent_day_timezone || 'UTC'
  ).getTime();
  const targetTime = utcToZonedTime(
    event.start_time,
    parent_day_timezone || 'UTC'
  ).getTime();

  // if the event start time has already passed, don't add it to the queue
  if (currentTime > targetTime || !parent_day_timezone) {
    return;
  }

  eventRemindersQueue.add(
    event.event_id as string,
    {
      event,
      sender: currentUser.user_id,
    },

    {
      delay: targetTime - currentTime - 1800000, // 30 minutes before event
    }
  );
}

my worker looks like this

export function eventReminderWorker() {
  const worker = new Worker(
    'event-reminders',
    async (job) => {
      console.log('EVENT REMINDER WORKER RUNNING');
    },
    {
      connection: {
        host: process.env.REDIS_HOST,
        port: parseInt(process.env.REDIS_PORT as string),
        maxRetriesPerRequest: null,
        retryStrategy: function (times: number) {
          return Math.max(Math.min(Math.exp(times), 20000), 1000);
        },
      },
    }
  );
  worker.on('completed', (job) => {
    // console.log(`${job.id} has completed! at ${new Date()}`);
  });
  worker.on('failed', (job, err) => {
    console.log({ EVENT_REMINDER_WORKER_ERROR: err });
    console.log(`${job?.id} has failed with ${err.message}`);
  });

  process.on('SIGINT', async () => {
    await worker.close();
  });
}

mieradi avatar Dec 05 '23 20:12 mieradi

So is the code above working or are you getting the error still? and do you have the complete error stack of the error?

manast avatar Dec 06 '23 09:12 manast

@manast the code above works fine locally, but in prod the error I get is emitted from QueueEvents, and not from the worker. The worker never actually runs, which is the issue, and also is whats making this so hard to debug.

The error I get from queueEvents.on('failed'... is 3 has failed with reason Cannot read properties of undefined (reading 'forEach')

Here is what the server is logging:

Dec 5 06:48:43 PM  event reminder worker started
Dec 5 06:50:00 PM  A job with ID 3 is waiting
Dec 5 06:50:00 PM  Job 3 is now active; previous status was waiting
Dec 5 06:50:00 PM  3 has failed with reason Cannot read properties of undefined (reading 'forEach')

Here is the QueueEvents code

  const queueEvents = new QueueEvents('event-reminders', {
    connection: {
      host: process.env.REDIS_HOST,
      port: parseInt(process.env.REDIS_PORT as string),
    },
  });

  queueEvents.on('completed', ({ jobId }) => {
    console.log('done painting');
  });

  queueEvents.on(
    'failed',
    ({ jobId, failedReason }: { jobId: string; failedReason: string }) => {
      console.error('error painting', failedReason);
    }
  );

mieradi avatar Dec 06 '23 13:12 mieradi

@manast any possible solutions on this?

mieradi avatar Dec 09 '23 13:12 mieradi

Unfortunatelly there is not a lot information here for us to take any action...

manast avatar Dec 22 '23 10:12 manast