node-schedule 1.2.5 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -2,7 +2,8 @@
2
2
 
3
3
  [![NPM version](http://img.shields.io/npm/v/node-schedule.svg)](https://www.npmjs.com/package/node-schedule)
4
4
  [![Downloads](https://img.shields.io/npm/dm/node-schedule.svg)](https://www.npmjs.com/package/node-schedule)
5
- [![Build Status](https://travis-ci.org/node-schedule/node-schedule.svg?branch=master)](https://travis-ci.org/node-schedule/node-schedule)
5
+ [![Build Status](https://github.com/node-schedule/node-schedule/workflows/ci/badge.svg)](https://github.com/node-schedule/node-schedule/actions)
6
+ [![Coverage Status](https://coveralls.io/repos/node-schedule/node-schedule/badge.svg?branch=master)](https://coveralls.io/r/node-schedule/node-schedule?branch=master)
6
7
  [![Join the chat at https://gitter.im/node-schedule/node-schedule](https://img.shields.io/badge/gitter-chat-green.svg)](https://gitter.im/node-schedule/node-schedule?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
7
8
 
8
9
  [![NPM](https://nodei.co/npm/node-schedule.png?downloads=true)](https://nodei.co/npm/node-schedule/)
@@ -43,14 +44,19 @@ Every scheduled job in Node Schedule is represented by a `Job` object. You can
43
44
  create jobs manually, then execute the `schedule()` method to apply a schedule,
44
45
  or use the convenience function `scheduleJob()` as demonstrated below.
45
46
 
46
- `Job` objects are `EventEmitter`'s, and emit a `run` event after each execution.
47
- They also emit a `scheduled` event each time they're scheduled to run, and a
48
- `canceled` event when an invocation is canceled before it's executed (both events
49
- receive a JavaScript date object as a parameter). Note that jobs are scheduled the
50
- first time immediately, so if you create a job using the `scheduleJob()`
51
- convenience method, you'll miss the first `scheduled` event, but you can query the
52
- invocation manually (see below). Also note that `canceled` is the single-L American
53
- spelling.
47
+ `Job` objects are `EventEmitter`s, and emit the following events:
48
+ * A `run` event after each execution.
49
+ * A `scheduled` event each time they're scheduled to run.
50
+ * A `canceled` event when an invocation is canceled before it's executed.
51
+ Note that `canceled` is the single-L American spelling.
52
+ * An `error` event when a job invocation triggered by a schedule throws or returns
53
+ a rejected `Promise`.
54
+
55
+ (Both the `scheduled` and `canceled` events receive a JavaScript date object as
56
+ a parameter).
57
+ Note that jobs are scheduled the first time immediately, so if you create a job
58
+ using the `scheduleJob()` convenience method, you'll miss the first `scheduled`
59
+ event, but you can query the invocation manually (see below).
54
60
 
55
61
  ### Cron-style Scheduling
56
62
 
@@ -58,7 +64,7 @@ The cron format consists of:
58
64
  ```
59
65
  * * * * * *
60
66
  ┬ ┬ ┬ ┬ ┬ ┬
61
- │ │ │ │ │ |
67
+ │ │ │ │ │ │
62
68
  │ │ │ │ │ └ day of week (0 - 7) (0 or 7 is Sun)
63
69
  │ │ │ │ └───── month (1 - 12)
64
70
  │ │ │ └────────── day of month (1 - 31)
@@ -89,11 +95,18 @@ var j = schedule.scheduleJob('0 17 ? * 0,4-6', function(){
89
95
 
90
96
  Execute a cron job every 5 Minutes = */5 * * * *
91
97
 
98
+ You can also get when it is scheduled to run for every invocation of the job:
99
+ ```js
100
+ var j = schedule.scheduleJob('0 1 * * *', function(fireDate){
101
+ console.log('This job was supposed to run at ' + fireDate + ', but actually ran at ' + new Date());
102
+ });
103
+ ```
104
+ This is useful when you need to check if there is a delay of the job invocation when the system is busy, or save a record of all invocations of a job for audit purpose.
92
105
  #### Unsupported Cron Features
93
106
 
94
- Currently, `W` (nearest weekday), `L` (last day of month/week), and `#` (nth weekday
95
- of the month) are not supported. Most other features supported by popular cron
96
- implementations should work just fine.
107
+ Currently, `W` (nearest weekday) and `L` (last day of month/week) are not supported.
108
+ Most other features supported by popular cron implementations should work just fine,
109
+ including `#` (nth weekday of the month).
97
110
 
98
111
  [cron-parser] is used to parse crontab instructions.
99
112
 
@@ -156,15 +169,31 @@ var j = schedule.scheduleJob(rule, function(){
156
169
  });
157
170
  ```
158
171
 
172
+ Timezones are also supported. Here is an example of executing at the start of every day in the UTC timezone.
173
+
174
+ ```js
175
+ var rule = new schedule.RecurrenceRule();
176
+ rule.hour = 0;
177
+ rule.tz = 'Etc/UTC';
178
+
179
+ var j = schedule.scheduleJob(rule, function(){
180
+ console.log('A new day has begun in the UTC timezone!');
181
+ });
182
+ ```
183
+
184
+ A list of acceptable tz (timezone) values can be found at <https://en.wikipedia.org/wiki/List_of_tz_database_time_zones>
185
+
159
186
  #### RecurrenceRule properties
160
187
 
161
- - `second`
162
- - `minute`
163
- - `hour`
164
- - `date`
165
- - `month`
188
+ - `second (0-59)`
189
+ - `minute (0-59)`
190
+ - `hour (0-23)`
191
+ - `date (1-31)`
192
+ - `month (0-11)`
166
193
  - `year`
167
- - `dayOfWeek`
194
+ - `dayOfWeek (0-6) Starting with Sunday`
195
+ - `tz`
196
+
168
197
 
169
198
  > **Note**: It's worth noting that the default value of a component of a recurrence rule is
170
199
  > `null` (except for second, which is 0 for familiarity with cron). *If we did not
@@ -197,11 +226,11 @@ var j = schedule.scheduleJob({ start: startTime, end: endTime, rule: '*/1 * * *
197
226
 
198
227
  ### Handle Jobs and Job Invocations
199
228
 
200
- There are some function to get informations for a Job and to handle the Job and
229
+ There are some function to get information for a Job and to handle the Job and
201
230
  Invocations.
202
231
 
203
232
 
204
- #### job.cancel(reshedule)
233
+ #### job.cancel(reschedule)
205
234
  You can invalidate any job with the `cancel()` method:
206
235
 
207
236
  ```js
@@ -210,7 +239,7 @@ j.cancel();
210
239
  All planned invocations will be canceled. When you set the parameter ***reschedule***
211
240
  to true then the Job is newly scheduled afterwards.
212
241
 
213
- #### job.cancelNext(reshedule)
242
+ #### job.cancelNext(reschedule)
214
243
  This method invalidates the next planned invocation or the job.
215
244
  When you set the parameter ***reschedule*** to true then the Job is newly scheduled
216
245
  afterwards.
@@ -224,8 +253,9 @@ This method returns a Date object for the planned next Invocation for this Job.
224
253
 
225
254
  ## Contributing
226
255
 
227
- This module was originally developed by [Matt Patenaude], and is now maintained by
228
- [Tejas Manohar] and [other wonderful contributors].
256
+ This module was originally developed by [Matt Patenaude] who eventually passed over maintainer's mantle over to [Tejas Manohar].
257
+
258
+ Currently it is being maintained by [Igor Savin] and [our amazing community].
229
259
 
230
260
  We'd love to get your contributions. Individuals making significant and valuable
231
261
  contributions are given commit-access to the project to contribute as they see fit.
@@ -243,7 +273,8 @@ Licensed under the **[MIT License] [license]**.
243
273
  [Contributing]: https://github.com/node-schedule/node-schedule/blob/master/CONTRIBUTING.md
244
274
  [Matt Patenaude]: https://github.com/mattpat
245
275
  [Tejas Manohar]: http://tejas.io
276
+ [Igor Savin]: https://twitter.com/kibertoad
246
277
  [license]: https://github.com/node-schedule/node-schedule/blob/master/LICENSE
247
278
  [Tejas Manohar]: https://github.com/tejasmanohar
248
- [other wonderful contributors]: https://github.com/node-schedule/node-schedule/graphs/contributors
279
+ [our amazing community]: https://github.com/node-schedule/node-schedule/graphs/contributors
249
280
  [cron-parser]: https://github.com/harrisiirak/cron-parser
@@ -0,0 +1,30 @@
1
+ 'use strict'
2
+
3
+ var nodeVersionString = process.versions.node
4
+
5
+ function getNodeVersion(nodeVersionString) {
6
+ var versionSplit = nodeVersionString.split('.')
7
+ return {
8
+ majorVersion: Number(versionSplit[0]),
9
+ minorVersion: Number(versionSplit[1])
10
+ }
11
+ }
12
+
13
+ function arePromisesSupported(nodeVersion) {
14
+ var majorVersion = nodeVersion.majorVersion
15
+ var minorVersion = nodeVersion.minorVersion
16
+
17
+ if (majorVersion > 0) {
18
+ return true
19
+ }
20
+
21
+ if (minorVersion < 12) {
22
+ return false
23
+ }
24
+
25
+ return true
26
+ }
27
+
28
+ module.exports.nodeVersionString = nodeVersionString;
29
+ module.exports.arePromisesSupported = arePromisesSupported;
30
+ module.exports.getNodeVersion = getNodeVersion;
package/lib/schedule.js CHANGED
@@ -11,11 +11,13 @@ var events = require('events'),
11
11
  cronParser = require('cron-parser'),
12
12
  CronDate = require('cron-parser/lib/date'),
13
13
  lt = require('long-timeout'),
14
- sorted = require('sorted-array-functions');
14
+ sorted = require('sorted-array-functions'),
15
+ nodeVersionUtils = require('./nodeVersionUtils')
15
16
 
16
17
  /* Job object */
17
18
  var anonJobCounter = 0;
18
19
  var scheduledJobs = {};
20
+ var promisesSupported = nodeVersionUtils.arePromisesSupported(nodeVersionUtils.getNodeVersion(nodeVersionUtils.nodeVersionString))
19
21
 
20
22
  function isValidDate(date) {
21
23
  // Taken from http://stackoverflow.com/a/12372720/1562178
@@ -90,7 +92,7 @@ function Job(name, job, callback) {
90
92
 
91
93
  cancelInvocation(inv);
92
94
 
93
- if (reschedule && inv.recurrenceRule.recurs) {
95
+ if (reschedule && (inv.recurrenceRule.recurs || inv.recurrenceRule.next)) {
94
96
  newInv = scheduleNextRecurrence(inv.recurrenceRule, this, inv.fireDate, inv.endDate);
95
97
  if (newInv !== null) {
96
98
  newInvs.push(newInv);
@@ -125,7 +127,7 @@ function Job(name, job, callback) {
125
127
 
126
128
  cancelInvocation(nextInv);
127
129
 
128
- if (reschedule && nextInv.recurrenceRule.recurs) {
130
+ if (reschedule && (nextInv.recurrenceRule.recurs || nextInv.recurrenceRule.next)) {
129
131
  newInv = scheduleNextRecurrence(nextInv.recurrenceRule, this, nextInv.fireDate, nextInv.endDate);
130
132
  if (newInv !== null) {
131
133
  this.trackInvocation(newInv);
@@ -167,12 +169,12 @@ function Job(name, job, callback) {
167
169
 
168
170
  util.inherits(Job, events.EventEmitter);
169
171
 
170
- Job.prototype.invoke = function() {
172
+ Job.prototype.invoke = function(fireDate) {
171
173
  if (typeof this.job == 'function') {
172
174
  this.setTriggeredJobs(this.triggeredJobs() + 1);
173
- this.job();
175
+ return this.job(fireDate);
174
176
  } else {
175
- this.job.execute();
177
+ this.job.execute(fireDate);
176
178
  }
177
179
  };
178
180
 
@@ -188,10 +190,14 @@ Job.prototype.schedule = function(spec) {
188
190
  var end;
189
191
  var tz;
190
192
 
193
+ // save passed-in value before 'spec' is replaced
194
+ if (typeof spec === 'object' && 'tz' in spec) {
195
+ tz = spec.tz;
196
+ }
197
+
191
198
  if (typeof spec === 'object' && spec.rule) {
192
199
  start = spec.start || undefined;
193
200
  end = spec.end || undefined;
194
- tz = spec.tz;
195
201
  spec = spec.rule;
196
202
 
197
203
  if (start) {
@@ -398,6 +404,11 @@ RecurrenceRule.prototype.isValid = function() {
398
404
  };
399
405
 
400
406
  RecurrenceRule.prototype.nextInvocationDate = function(base) {
407
+ var next = this._nextInvocationDate(base);
408
+ return next ? next.toDate() : null;
409
+ };
410
+
411
+ RecurrenceRule.prototype._nextInvocationDate = function(base) {
401
412
  base = ((base instanceof CronDate) || (base instanceof Date)) ? base : (new Date());
402
413
  if (!this.recurs) {
403
414
  return null;
@@ -464,7 +475,7 @@ RecurrenceRule.prototype.nextInvocationDate = function(base) {
464
475
  break;
465
476
  }
466
477
 
467
- return next ? next.toDate() : null;
478
+ return next;
468
479
  };
469
480
 
470
481
  function recurMatch(val, matcher) {
@@ -491,10 +502,15 @@ function recurMatch(val, matcher) {
491
502
 
492
503
  /* Date-based scheduler */
493
504
  function runOnDate(date, job) {
494
- var now = (new Date()).getTime();
505
+ var now = Date.now();
495
506
  var then = date.getTime();
496
-
497
- return lt.setTimeout(job, (then < now ? 0 : then - now));
507
+
508
+ return lt.setTimeout(function() {
509
+ if (then > Date.now())
510
+ runOnDate(date, job);
511
+ else
512
+ job();
513
+ }, (then < now ? 0 : then - now));
498
514
  }
499
515
 
500
516
  var invocations = [];
@@ -535,8 +551,18 @@ function prepareNextInvocation() {
535
551
 
536
552
  job.stopTrackingInvocation(cinv);
537
553
 
538
- job.invoke();
539
- job.emit('run');
554
+ try {
555
+ var result = job.invoke(cinv.fireDate instanceof CronDate ? cinv.fireDate.toDate() : cinv.fireDate);
556
+ job.emit('run');
557
+
558
+ if (promisesSupported && result instanceof Promise) {
559
+ result.catch(function (err) {
560
+ job.emit('error', err);
561
+ });
562
+ }
563
+ } catch (err) {
564
+ job.emit('error', err);
565
+ }
540
566
  });
541
567
  }
542
568
  }
@@ -569,7 +595,7 @@ function scheduleNextRecurrence(rule, job, prevDate, endDate) {
569
595
 
570
596
  prevDate = (prevDate instanceof CronDate) ? prevDate : new CronDate();
571
597
 
572
- var date = (rule instanceof RecurrenceRule) ? rule.nextInvocationDate(prevDate) : rule.next();
598
+ var date = (rule instanceof RecurrenceRule) ? rule._nextInvocationDate(prevDate) : rule.next();
573
599
  if (date === null) {
574
600
  return null;
575
601
  }
package/package.json CHANGED
@@ -1,38 +1,52 @@
1
1
  {
2
2
  "name": "node-schedule",
3
- "version": "1.2.5",
3
+ "version": "1.3.3",
4
4
  "description": "A cron-like and not-cron-like job scheduler for Node.",
5
5
  "keywords": [
6
6
  "schedule",
7
7
  "task",
8
8
  "job",
9
- "cron"
9
+ "cron",
10
+ "in-memory"
10
11
  ],
11
12
  "license": "MIT",
12
13
  "main": "./lib/schedule.js",
13
14
  "scripts": {
14
15
  "test": "nodeunit",
15
- "lint": "eslint lib test"
16
+ "test:coverage": "istanbul cover ./node_modules/.bin/nodeunit test",
17
+ "test:coverage-win": "istanbul cover ./node_modules/nodeunit/bin/nodeunit test",
18
+ "lint": "eslint lib test",
19
+ "lint:fix": "eslint --fix lib test"
16
20
  },
17
21
  "author": {
18
22
  "name": "Matt Patenaude",
19
23
  "email": "matt@mattpatenaude.com",
20
24
  "url": "http://mattpatenaude.com"
21
25
  },
26
+ "contributors": [
27
+ {
28
+ "name": "Igor Savin",
29
+ "email": "kibertoad@gmail.com"
30
+ }
31
+ ],
22
32
  "repository": {
23
33
  "type": "git",
24
34
  "url": "https://github.com/node-schedule/node-schedule.git"
25
35
  },
26
36
  "dependencies": {
27
- "cron-parser": "^2.4.0",
37
+ "cron-parser": "^2.18.0",
28
38
  "long-timeout": "0.1.1",
29
- "sorted-array-functions": "^1.0.0"
39
+ "sorted-array-functions": "^1.3.0"
30
40
  },
31
41
  "devDependencies": {
32
- "coveralls": "^2.11.2",
33
- "eslint": "^3.19.0",
42
+ "eslint": "^7.18.0",
34
43
  "istanbul": "^0.4.5",
35
- "nodeunit": "^0.10.2",
36
- "sinon": "^1.14.1"
37
- }
44
+ "nodeunit": "~0.10.2",
45
+ "sinon": "^2.4.1"
46
+ },
47
+ "files": [
48
+ "README.md",
49
+ "LICENSE",
50
+ "lib/*"
51
+ ]
38
52
  }
package/.eslintrc DELETED
@@ -1,17 +0,0 @@
1
- {
2
- "env": {
3
- "node": true,
4
- "es6": true
5
- },
6
- "rules": {
7
- "eqeqeq": ["error", "smart"],
8
- "indent": ["error", 2, { "SwitchCase": 1 }],
9
- "no-constant-condition": "off",
10
- "no-redeclare": "warn",
11
- "no-underscore-dangle": "off",
12
- "no-use-before-define": ["warn","nofunc"],
13
- "quotes": ["error", "single"],
14
- "space-before-blocks": "error",
15
- "strict": "error"
16
- }
17
- }
package/.travis.yml DELETED
@@ -1,15 +0,0 @@
1
- language: node_js
2
- node_js:
3
- - "0.12"
4
- - "0.10"
5
- - "4"
6
- - "6"
7
- - "7"
8
- before_script: >
9
- if nvm ls-remote --lts | grep "$(nvm current)"; then
10
- echo "running on a LTS node version, linting"
11
- npm test
12
- else
13
- echo "running on a non-LTS node version, skipping linting"
14
- fi
15
- script: ./node_modules/.bin/istanbul cover ./node_modules/.bin/nodeunit test && cat ./coverage/lcov.info | ./node_modules/.bin/coveralls && rm -rf ./coverage
package/CONTRIBUTING.md DELETED
@@ -1,31 +0,0 @@
1
- ## Rules
2
- 1. **No `--force` pushes** or modifying the git history in any way
3
- 2. Follow existing code style
4
- 3. Pull requests with tests are much more likely to be accepted
5
- 4. Follow the guidelines below
6
-
7
- ## Bugfix or Feature?
8
-
9
- This project uses the [gitflow workflow](https://www.atlassian.com/git/tutorials/comparing-workflows/gitflow-workflow). Simply put, you need to decide if your contribution will be a bug fix that could be released as a patch, or a feature that will end up being a minor or major release.
10
-
11
- ### Found a bug that can be fixed without affecting the API?
12
-
13
- 1. **Fork** this repo
14
- 2. Create a new branch from `master` to work in
15
- 3. **Add tests** if needed
16
- 4. Make sure your code **lints** by running `npm run lint`
17
- 5. Make sure your code **passes tests** by running `npm test`
18
- 6. Submit a **pull request** against the `master` branch
19
-
20
- ### New feature or anything that would result in a change to the API?
21
-
22
- 1. **Fork** this repo
23
- 2. Create a new branch from `develop` to work in
24
- 3. **Add tests** to as needed
25
- 4. Make sure your code **lints** by running `npm run lint`
26
- 5. Make sure your code **passes tests** by running `npm test`
27
- 6. Submit a **pull request** against the `develop` branch
28
-
29
- ## Releases
30
-
31
- Declaring formal releases remains the prerogative of the project maintainer.