Планирование задач (резервное копирование) с учетом часового пояса и летнего времени каждого пользователя

#android #ios #node.js #cron #scheduled-tasks

#Android #iOS #node.js #cron #запланированные задачи

Вопрос:

У меня есть собственные приложения для Android и iOS, разработанные с помощью NodeJS для внутренних веб-сервисов. Что мне нужно, так это создавать резервные копии пользовательских данных каждую полночь. Я знаю, что это можно сделать на серверной части с помощью cron, но я хочу, чтобы резервное копирование было привязано к часовым поясам (т. Е. Резервное копирование должно выполняться в полночь «в регионе / часовом поясе пользователя»).).

Каков наилучший способ сделать это?

  • Должен ли планировщик быть в интерфейсе?
    Запуск веб-службы в полночь
    Проблема с этим подходом возникает, когда приложение закрыто или телефон выключен

  • Должен ли планировщик быть на серверной части?
    Запишите часовой пояс каждого пользователя в базу данных и используйте задания cron для резервного
    копирования Как это сделать, учитывая, что также может быть переход на летнее время!

Я хочу, чтобы заданная резервная копия соответствовала часовому поясу каждого пользователя!

До сих пор я пытался работать на серверной части, поскольку она наиболее подходит, удобна и имеет наименьшие шансы на сбой (ничего нельзя сделать на интерфейсной части, если телефон выключен или недоступен для сети).). Я использовал node-cron для заданий cron. Но я хочу знать, какую частоту я должен установить для запуска в 00: 01 в каждом часовом поясе, учитывая летнее время. Невозможно настроить почасовую частоту, поскольку некоторые часовые пояса составляют 30 минут ( 05:30), некоторые — 15 и некоторые — 45 минут. Также как создавать резервные копии только тех пользователей, которые принадлежат к этому часовому поясу?

Ответ №1:

Я бы предложил использовать библиотеку cron для этой цели, а не node-cron, поскольку последняя фактически не обрабатывает летнее время должным образом (она использует фиксированные смещения UTC, которые не будут работать для каждого часового пояса).

Затем вы можете создать задание для каждого часового пояса для запуска резервных копий. При этом каждое резервное копирование будет выполняться в 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);
  

Комментарии:

1. Я думаю, что отдельное задание для каждого пользователя приведет к слишком большому количеству заданий, выполняемых вместе, что может быть не лучшим решением для сервера. Разве это не может быть оптимизировано путем запуска cron в 00: 01 в каждом и каждом часовом поясе и объединения пользователей, принадлежащих к этому часовому поясу, вместе?

2. Конечно, это было мое следующее предложение, я обновлю ответ!

3. Я обновил, поэтому мы будем запускать задание для каждого часового пояса. Каждый объект спецификации содержит список пользователей для этого часового пояса.

4. Как я могу получить часовой пояс для пользователей в формате имени, например, America / New_York , в отличие от формата GMT -04:00 ? Потому что мобильный телефон предоставляет последний формат!

5. Ах да, это сложно. Проблема в том, что трудно преобразовать смещение UTC в идентификатор часового пояса, поскольку смещение UTC неоднозначно (может быть много идентификаторов часовых поясов с одинаковым смещением UTC). Формат GMT не дает нам достаточно данных для работы (например, смещения летнего времени и время перехода). Вы можете преобразовать в общий идентификатор часового пояса, например, «Etc / GMT 5» (что эквивалентно восточному стандартному времени). Существует риск того, что вы можете запустить резервное копирование на час позже или на час раньше, хотя я бы не подумал, что это огромная проблема.