diff --git a/src/cron.js b/src/cron.js index fb695fd34..ea2dc9803 100644 --- a/src/cron.js +++ b/src/cron.js @@ -28,6 +28,7 @@ const appHealthMonitor = require('./apphealthmonitor.js'), dyndns = require('./dyndns.js'), eventlog = require('./eventlog.js'), janitor = require('./janitor.js'), + paths = require('./paths.js'), safe = require('safetydance'), scheduler = require('./scheduler.js'), settings = require('./settings.js'), @@ -61,8 +62,21 @@ const gJobs = { // Months: 0-11 // Day of Week: 0-6 +function getCronSeed() { + let seedHour = parseInt(safe.fs.readFileSync(paths.CRON_SEED_FILE)); + if (!seedHour || seedHour < 0 || seedHour > 23) { + seedHour = Math.floor(Math.random()*24); + debug(`getCronSeed: writing new cron seed file with ${seedHour} to ${paths.CRON_SEED_FILE}`); + safe.fs.writeFileSync(paths.CRON_SEED_FILE, `${seedHour}`); + } + + return seedHour; +} + async function startJobs() { - debug('startJobs: starting cron jobs'); + const hourlySeed = getCronSeed(); + + debug(`startJobs: starting cron jobs with hourly offset seed ${hourlySeed}`); const randomTick = Math.floor(60*Math.random()); gJobs.systemChecks = new CronJob({ @@ -114,9 +128,9 @@ async function startJobs() { start: true }); - // randomized over minute an hours, once a day to not hammer Let'sEncrypt on the same schedule + // randomized per Cloudron based on hourlySeed gJobs.certificateRenew = new CronJob({ - cronTime: `00 ${parseInt(Math.random()*60)} ${parseInt(Math.random()*24)} * * *`, + cronTime: `00 10 ${hourlySeed} * * *`, onTick: async () => await safe(cloudron.renewCerts({}, AuditSource.CRON), { debug }), start: true }); diff --git a/src/paths.js b/src/paths.js index b74a2d345..19ed85fbe 100644 --- a/src/paths.js +++ b/src/paths.js @@ -16,6 +16,7 @@ exports = module.exports = { CLOUDRON_DEFAULT_AVATAR_FILE: path.join(__dirname + '/../assets/avatar.png'), INFRA_VERSION_FILE: path.join(baseDir(), 'platformdata/INFRA_VERSION'), + CRON_SEED_FILE: path.join(baseDir(), 'platformdata/CRON_SEED'), DASHBOARD_DIR: constants.TEST ? path.join(__dirname, '../../dashboard/src') : path.join(baseDir(), 'box/dashboard/dist'), PROVIDER_FILE: '/etc/cloudron/PROVIDER',