diff --git a/core/server/adapters/scheduling/SchedulingDefault.js b/core/server/adapters/scheduling/SchedulingDefault.js index 992a9ce8a4..c2727a2f2f 100644 --- a/core/server/adapters/scheduling/SchedulingDefault.js +++ b/core/server/adapters/scheduling/SchedulingDefault.js @@ -74,9 +74,24 @@ SchedulingDefault.prototype.schedule = function (object) { * oldTime: [Number] The previous published time. * } * } + * @param {Object} options + * { + * bootstrap: [Boolean] + * } */ -SchedulingDefault.prototype.reschedule = function (object) { - this._deleteJob({time: object.extra.oldTime, url: object.url}); +SchedulingDefault.prototype.reschedule = function (object, options = {bootstrap: false}) { + /** + * CASE: + * The post scheduling unit calls "reschedule" on bootstrap, because other custom scheduling implementations + * could use a database and we need to give the chance to update the job (delete + re-add). + * + * We receive a "bootstrap" variable to ensure that jobs are scheduled correctly for this scheduler implementation, + * because "object.extra.oldTime" === "object.time". If we mark the job as deleted, it won't get scheduled. + */ + if (!options.bootstrap) { + this._deleteJob({time: object.extra.oldTime, url: object.url}); + } + this._addJob(object); }; diff --git a/core/server/adapters/scheduling/post-scheduling/index.js b/core/server/adapters/scheduling/post-scheduling/index.js index e4ce448aa8..59c9d2fbff 100644 --- a/core/server/adapters/scheduling/post-scheduling/index.js +++ b/core/server/adapters/scheduling/post-scheduling/index.js @@ -86,7 +86,9 @@ exports.init = function init(options = {}) { } scheduledPosts.forEach((model) => { - adapter.reschedule(_private.normalize({model, apiUrl, client})); + // NOTE: We are using reschedule, because custom scheduling adapter could use a database, which needs to be updated + // and not an in-process implementation! + adapter.reschedule(_private.normalize({model, apiUrl, client}), {bootstrap: true}); }); }) .then(() => { diff --git a/core/test/unit/adapters/scheduling/SchedulingDefault_spec.js b/core/test/unit/adapters/scheduling/SchedulingDefault_spec.js index 1de0d5e818..72ede5309b 100644 --- a/core/test/unit/adapters/scheduling/SchedulingDefault_spec.js +++ b/core/test/unit/adapters/scheduling/SchedulingDefault_spec.js @@ -60,6 +60,55 @@ describe('Scheduling Default Adapter', function () { ]); }); + it('reschedule: default', function (done) { + sinon.stub(scope.adapter, '_pingUrl'); + + const time = moment().add(20, 'milliseconds').valueOf(); + + scope.adapter.schedule({ + time: time, + url: 'something', + extra: { + oldTime: null, + method: 'PUT' + } + }); + + scope.adapter.reschedule({ + time: time, + url: 'something', + extra: { + oldTime: time, + method: 'PUT' + } + }); + + setTimeout(() => { + scope.adapter._pingUrl.calledOnce.should.eql(true); + done(); + }, 50); + }); + + it('reschedule: simulate restart', function (done) { + sinon.stub(scope.adapter, '_pingUrl'); + + const time = moment().add(20, 'milliseconds').valueOf(); + + scope.adapter.reschedule({ + time: time, + url: 'something', + extra: { + oldTime: time, + method: 'PUT' + } + }, {bootstrap: true}); + + setTimeout(() => { + scope.adapter._pingUrl.calledOnce.should.eql(true); + done(); + }, 50); + }); + it('run', function (done) { // 1000 jobs, but only the number x are under 1 minute var timestamps = _.map(_.range(1000), function (i) {