首页 > 解决方案 > 处理每个用户的时区和 DST 的任务调度(运行备份)

问题描述

我有使用 NodeJS 为后端 Web 服务开发的原生 Android 和 iOS 应用程序。我需要的是每个午夜备份用户的数据。我知道它可以在后端使用 cron 完成,但我希望备份特定于时区(即备份应该在午夜“在用户的区域/时区”中进行)。

做这个的最好方式是什么?

我要根据每个用户的时区指定备份!

到目前为止,我已经尝试过在后端工作,因为它最合适、最方便且失败的可能性最小(如果手机关闭或网络无法连接,则无法在前端完成任何操作)。我已经将 node-cron用于 cron 作业。但我想知道我应该在每个时区的 00:01 设置什么频率运行,以照顾 DST。无法设置每小时频率,因为某些时区是 30 分钟 (+05:30),有些是 15 分钟,有些是 45 分钟。另外如何仅备份属于该时区的那些用户?

标签: androidiosnode.jscronscheduled-tasks

解决方案


我建议为此目的使用cron库而不是node-cron,因为后者实际上并不能正确处理 DST(它使用固定的 UTC 偏移量,这并不适用于每个时区)。

然后,您可以为每个时区创建一个作业来运行备份。这将在包含 DST 更改的本地时区的 00:01 运行每个备份,如果您使用 spec.users 遍历每个用户,则可以备份他们的数据。

const CronJob = require("cron").CronJob;
const parser = require('cron-parser');

const cronExpression = "01 00 * * *";

let users = [ 
    { name: "user 1", timeZone: "America/New_York"},
    { name: "user 2", timeZone: "Europe/Berlin"},
    { name: "user 3", timeZone: "America/New_York"},
    { name: "user 4", timeZone: "Asia/Kolkata"},
]

let backUpJobSpecs = users.reduce((jobs, user) => { 
    let job = jobs.find(job => job.timeZone === user.timeZone);
    if (!job) {
        job = { timeZone: user.timeZone, cronExpression, users: []}
        jobs.push(job);
    }
    job.users.push(user);
    return jobs;
}, []);

function startBackupJobs() {
    let timeZones = [...new Set(backUpJobSpecs.map(({timeZone}) => timeZone))];
    let jobs = backUpJobSpecs.map(createJobFromSpec);
    console.log(`startBackupJobs: ${jobs.length} backup job(s) started for ${timeZones.length} timezone(s)...`);
    console.log(`startBackupJobs: Timezone list: ${timeZones.join(", ")}`);
}

function logTimeUntilBackups() {
    console.log(`${'Timezone'.padEnd(21)}${'Users'.padEnd(21)}Next backup (hours)`);
    backUpJobSpecs.forEach(job => console.log(`${job.timeZone.padEnd(20)}`,`${(job.users.length+"").padEnd(20)}`, Math.round((parser.parseExpression(cronExpression, { tz: job.timeZone }).next().getTime()  - new Date().getTime() ) / 3600000 )) );
}

function createJobFromSpec(spec) {
    return new CronJob(
        spec.cronExpression,
        () => {
            runBackup(spec)
        },
        null,
        true,
        spec.timeZone
    );
}

function runBackup(spec) {
    console.log(`Backup running now for timezone: ${spec.timeZone}`);
    console.log("Local time: "  + new Date().toLocaleString("en", { timeZone: spec.timeZone  }));
    console.log("UTC time: "  + new Date().toISOString());
}

startBackupJobs();
logTimeUntilBackups();
setInterval(logTimeUntilBackups, 60000);

推荐阅读