Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Patch for issue #41 #42

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,29 @@ To start processing your jobs, somewhere in your project add:
SyncedCron.start();
```

If you want a job to run only once or a limited number of times, you can either remove it inside the job function or create a limited schedule:

```javascript
SyncedCron.add({
name: 'myJob',
schedule: function(parser) {
// EITHER set a limited schedule
var date = new Date;
date.setHours(date.getHours() + 12);

// (this Later.js object only contains a single event)
return parser.recur().on(date).fullDate();
},
job: function() {
// (do something)

// ... OR remove the job inside function
SyncedCron.remove('myJob');
}
});
```


### Advanced

SyncedCron uses a collection called `cronHistory` to syncronize between processes. This also serves as a useful log of when jobs ran along with their output or error. A sample item looks like:
Expand Down
48 changes: 29 additions & 19 deletions synced-cron-server.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,7 @@ Meteor.startup(function() {
var scheduleEntry = function(entry) {
var schedule = entry.schedule(Later.parse);
entry._timer =
SyncedCron._laterSetInterval(SyncedCron._entryWrapper(entry), schedule);
SyncedCron._laterSetInterval(SyncedCron._entryWrapper(entry), schedule, entry.name);

log.info('Scheduled "' + entry.name + '" next run @'
+ Later.schedule(schedule).next(1));
Expand Down Expand Up @@ -238,20 +238,22 @@ SyncedCron._reset = function() {
// between multiple, potentially laggy and unsynced machines

// From: https://github.com/bunkat/later/blob/master/src/core/setinterval.js
SyncedCron._laterSetInterval = function(fn, sched) {
SyncedCron._laterSetInterval = function(fn, sched, name) {

var t = SyncedCron._laterSetTimeout(scheduleTimeout, sched),
var t = SyncedCron._laterSetTimeout(scheduleTimeout, sched, name),
done = false;

/**
* Executes the specified function and then sets the timeout for the next
* interval.
*/
function scheduleTimeout(intendedAt) {
if(!done) {
if (!done)
fn(intendedAt);
t = SyncedCron._laterSetTimeout(scheduleTimeout, sched);
}

// Check for done again, in case entry is removed inside job function body
if (!done)
t = SyncedCron._laterSetTimeout(scheduleTimeout, sched, name);
}

return {
Expand All @@ -269,7 +271,7 @@ SyncedCron._laterSetInterval = function(fn, sched) {
};

// From: https://github.com/bunkat/later/blob/master/src/core/settimeout.js
SyncedCron._laterSetTimeout = function(fn, sched) {
SyncedCron._laterSetTimeout = function(fn, sched, name) {

var s = Later.schedule(sched), t;
scheduleTimeout();
Expand All @@ -281,21 +283,29 @@ SyncedCron._laterSetTimeout = function(fn, sched) {
*/
function scheduleTimeout() {
var now = Date.now(),
next = s.next(2, now),
diff = next[0].getTime() - now,
intendedAt = next[0];

// minimum time to fire is one second, use next occurrence instead
if(diff < 1000) {
diff = next[1].getTime() - now;
intendedAt = next[1];
}
next = s.next(2, now);

if(diff < 2147483647) {
t = Meteor.setTimeout(function() { fn(intendedAt); }, diff);
if (next) {
var diff = next[0].getTime() - now,
intendedAt = next[0];

// minimum time to fire is one second, use next occurrence instead
if(next[1] && diff < 1000) {
diff = next[1].getTime() - now;
intendedAt = next[1];
}

if(diff < 2147483647) {
t = Meteor.setTimeout(function() { fn(intendedAt); }, diff);
}
else {
t = Meteor.setTimeout(scheduleTimeout, 2147483647);
}
}
else {
t = Meteor.setTimeout(scheduleTimeout, 2147483647);
log.info('SyncedCron: No more future events for "' + name + '".');

SyncedCron.remove(name);
}
}

Expand Down
42 changes: 42 additions & 0 deletions synced-cron-tests.js
Original file line number Diff line number Diff line change
Expand Up @@ -183,3 +183,45 @@ Tinytest.addAsync('SyncedCron should pass correct arguments to logger', function

SyncedCron.options.logger = null;
});


/*
Unfinished tests
*/

Tinytest.add('Removing current entry inside job prevents the next event from running', function(test) {
//! Preparation

SyncedCron.add({
name: "testRemove",
schedule: function (parser) {
return parser.recur().every(1).second();
},
job: function () {
console.log("TEST");
SyncedCron.remove("testRemove");
}
});

//! Should test that "TEST" is only output to log once
});

Tinytest.add('Automatically remove entry after last event in schedule has been triggered', function(test) {
//! Preparation

SyncedCron.add({
name: "testRemove",
schedule: function (parser) {
var date = new Date;
date.setSeconds(date.getSeconds() + 2);

return parser.recur().on(date).fullDate();
},
job: function () {
console.log("TEST");
}
});

//! Should test that "TEST" is only output to log once
// and that "testRemove" is removed after 2 seconds
});