Search code examples
node.jsmongodbagenda

How `agenda.js` calculates timezone for `every()` operation


I am using agenda.js in my Node project, backed with a MongoDB database, to handle batch processes we need to run. This is working well. I do have a question about timezones, however. When I use the every() operation, it seems like it accepts the job name, and the schedule. So I have been seeding jobs to the database like so:

  for (let job of dbJobs) {
    await agenda.every(schedule, job.name);
  }

Note that for the above, schedule is in cron format -- 00 05 * * 1-5.

This works. However, from what I can tell, every() doesn't accept an argument for repeatTimezone. So what does it do to calculate the timezone in those cases?

To clarify, when I look at the document in the database after the job has been added using every(), the repeatTimezone property exists, but its value is set to null.

Other agenda operations, like repeatEvery(), do accept an argument for timezone, like so:

job.repeatEvery('0 6 * * *', {
  timezone: 'America/New_York'
});

Since I'm using every(), I have been managing this by first seeding the database using every(), and then running a Mongo updateMany() to add the timzeone explicitly to all jobs:

async function addTimezoneToJobs() {
  try {
    const db = await client.db(dbName);
    await db.collection('batch_processes').updateMany({}, {
      $set: {
        repeatTimezone: 'America/New_York'
      }
    });
  } catch (error) {
    console.log(error);
  }
}

But strangely enough, agenda seems to calculate the same time even when I don't explicitly add the repeatTimezone property value to the jobs as when I do.

What's happening here that I'm not understanding? How is the runtime calculated with every(), and is there a way to pass in timezone?

FYI: I am not in the same timezone as that which needs to be set in the db.


Solution

  • Your Question seems to be 2 part, I'm not exactly sure I'll be able to explain it very well but let me try

    So, your first question

    However, from what I can tell, every() doesn't accept an argument for Timezone

    Well Technically you can add Timezone option to every() as well because what this method does is it calls job.repeatEvery internally and as you already know you can add timezone to that. To Support my answer, I found 2 evidence

    1. From Documentation as every accepts 4 parameters

    every(interval, name, [data], [options])

    options is an optional argument that will be passed to job.repeatEvery. In order to use this argument, data must also be specified.

    So you can technically pass timezone if you pass data as well

    1. From SourceCode, here you can see they use job.repeatEvery(interval, options) internally.

    Now, To your Second Question

    what does it do to calculate the timezone in those cases?

    Well They have a very unique yet required module named ComputeNextRunAt().

    So I went through their Source Code and figured Out that this is to Compute when will be the next run for your job based on startingTime and Interval.

    Your Code works because you have once (Initially) mentioned in your job to follow America/New_York timezone, so every next job interval is calculated based on that, that's the reason you don't need to specify it again.

    So, If initially you haven't had specified the timezone attribute, you would have gotten your local Timezone but now you did so, it calculates the next interval based on that.