Agenda: repeatAt

Created on 6 Oct 2014  路  23Comments  路  Source: agenda/agenda

Hello guys;
if I set a job like this:

var job = agenda.create(type);
job.repeatAt('at 19:43');
job.save();

After 19:43 (when the job has done its work) if i see the document saved into MongoDB I take this:

> db.jobs.find().pretty();
{
        "_id" : ObjectId("5432d5903b8004b017dfeff5"),
        "name" : "someTask",
        "data" : null,
        "type" : "normal",
        "priority" : 0,
        "nextRunAt" : null,
        "repeatAt" : "at 19:48",
        "lastModifiedBy" : null,
        "lockedAt" : null,
        "lastRunAt" : ISODate("2014-10-06T17:48:00.998Z"),
        "lastFinishedAt" : ISODate("2014-10-06T17:48:01Z"),
        "failReason" : "failed to calculate repeatAt time due to invalid format",
        "failedAt" : ISODate("2014-10-06T17:48:00.998Z")
}

with a fail reason.
So I believe tha job will not reRun the tomorrow day at 19:43, right?
Any hint?

Gabri

bug waiting for response

Most helpful comment

Hey all I got around this issue by setting it up like so:

var job = agenda.create('sync');
job.schedule('today at 9:00pm');
job.repeatAt('tomorrow 9:00pm');

All 23 comments

@gabrieledarrigo instead of

job.repeatAt('at 19:43');

try

job.repeatAt('19:43');

Also, you are correct, the job will not re-run because of the error.

Hello @rschmukler I've already tried that, it's the same.
I've seen that it not happens every time. It's strange 'cause I've searched for the error into the source code and I found this.

if(Date.now() == date(repeatAt).valueOf()) {
      this.attrs.nextRunAt = undefined;
      this.fail('failed to calculate repeatAt time due to invalid format');
} else if(nextDate.valueOf() == lastRun.valueOf()) {
      this.attrs.nextRunAt = date('tomorrow at ', repeatAt);
 } else {
      this.attrs.nextRunAt = date(repeatAt);
 }

So does it enter in the first condition?
A question: If I set a job with

job.repeatAt('19:43');

and I stop the server at 19:40 and I restart the server at 19:45;
the job will run the tomorrow day at 19:43 or it will not start because nextRunAt is a date in the past?
Thank you for you help : )

Gabri

My guess is that what is happening is that the job is completing in less than 1ms and so the time of repeatAt is the same as current time.

@nwkeeley why did you do the Date.now() check? Is there a better way? Perhaps moving the second if statement to execute first?

@rschmukler Mhh that's true, I didn't think that!
Anyway, about my last question, does the job run the tomorrow day if accidentaly the server goes down
at 19:40 (with the job setted with repeatAt 19:43) and come up at 19:45?
Thanks!

So repeatAt and repeatEvery both are just used to compute nextRunAt - and then agenda looks for jobs with nextRunAt < Date.now()... So in those cases, the server will run the jobs because 19:43 < 19:45

@rschmukler @gabrieledarrigo
Actually date.js module does not set milliseconds to 0 when parsing values. Therefore, if job is completed within 1 second (not 1ms), you get "failed to calculate repeatAt time due to invalid format".

Run following script to see that milliseconds always match:

var date = require("date.js");
setInterval(function() {
    console.log(Date.now(), date('19:43').valueOf())
}, 100);

I have worked around this issue by adding "tomorrow", e.g. repeatAt("tomorrow 11:00am")

Apologies just looking at this now.... I think there is still an issue with how computeFromRepeatAt() returns the this.attrs.nextRunAt... I am going to try and investigate this weekend.

Any update on this issue? I get this failure every single time with repeatAt:

"failed to calculate repeatAt time due to invalid format"

Hey all, I am also getting this error, any updates? Thanks!

Ok it actually seems like this is really Date.js's fault (https://github.com/datejs/Datejs): if the string passed to date() is bad, it will return the current date... even though really it should be failing... seems really silly.

Since agenda checks every minute from what I can gather, if you set `job.repeatAt('9:00pm'); then when it runs at 21:00:00 it will equal the current date, 21:00:00

The fix for this is to set seconds AFTER 0 to the job: job.repeatAt('9:00:01pm'); so when it runs at 21:00:00 it will not be equal to 21:00:01

Can anybody confirm?

Hey all I got around this issue by setting it up like so:

var job = agenda.create('sync');
job.schedule('today at 9:00pm');
job.repeatAt('tomorrow 9:00pm');

Hm nice @btknorr. Does it work tomorrow for sure?

yep been using this for a while now :)

I got the same error btw...

failed to calculate repeatAt time due to invalid format

Turns out my method mentioned above is also not working

Is there any case where you can't replace "job.repeatAt" with a clever use of "job.repeatEvery" and "job.schedule"? e.g. instead of job.repeatAt('1:00am') you could set job.schedule('tomorrow at 1:00am') and job.repeatEvery('1 day') and get the desired effect. Am I missing something?

Yes I believe this will work. Personally though I try not to rely on job nesting.. to be safe (:

@avivroth if you do your approach and the job runs at 1am it will then reschedule and run again at 1am the next day.

However if the server goes down at 12am, comes back online at 5am your job will run right away. The problem with repeatEvery is that it simply adds 24hrs to the last time it executed.

RepeatAt maintains the time even if there is a server outage.

I went through the same issue, however, @btknorr solution worked well for me.
I am not doing anything fancy with date formats, following the same example as showing in the repeatAt section in documentations

agenda.define(name, function (job, done) {
      logger.info('Executing job with data: %j', job.attrs.data);
      setTimeout(function () {
       console.log('Processing done...');
        done();
      }, 10000);
    });

var job = agenda.create(name, data);
job.repeatAt('3:30pm');
job.save();

As you can see I tried to put done in a callback to increase processing time as fast execution might be one of the reasons as pointed by @rschmukler , however, it didn't solve the issue.

Could that be related to function(job,done) doesn't block until done gets called ?

Async Job:

agenda.define('some long running job', function(job, done) {
  doSomelengthyTask(function(data) {
    formatThatData(data);
    sendThatData(data);
    done();
  });
});

Sync Job:

agenda.define('say hello', function(job) {
  console.log("Hello!");
});

@agenda/maintainers I think we need to add better validation for time/date formats so invalid formats are detected before adding to the db.

Hi all. Did you fixed this problem ?

No, not yet, I've gotten busy with some other things and haven't had a chance to get back to it.

Worked for me after using cron time format instead of human-readable: '2:30am' -> '30 2 * * *'. This approach works fine with time zone as well.

Surprisingly this weird issue has been opened for 4 years :O

Thanks @btknorr

Was this page helpful?
0 / 5 - 0 ratings

Related issues

Relecto picture Relecto  路  12Comments

mbadam-equinix picture mbadam-equinix  路  39Comments

OmgImAlexis picture OmgImAlexis  路  14Comments

niftylettuce picture niftylettuce  路  21Comments

lucazulian picture lucazulian  路  21Comments