Периодическое расписание — это круто, это, вероятно, наиболее часто используемое и распространенное расписание cron. Например, рутинные задачи, такие как очистка, отправка информационных бюллетеней по электронной почте, должны выполняться ежедневно/еженедельно/ежемесячно.
Периодический график работает на неопределенный срок. Вопрос: Как нам это остановить? Эта статья о том, как это сделать на самом деле.
Обычно это абстрактный тип данных (ADT) со следующими свойствами.
- start_date — дата выполнения.
- duration — период до следующего выполнения.
Мотивация?
- поощрительная программа с датой окончания...
- рекламная программа с датой окончания…
- или, в основном, любые задания, которые заканчиваются в расписании.
Одно из возможных решений — Expires_at
Один из способов решить эту проблему — ввести новое свойство: expires_at. Выполнять задания до сейчас( ) ≥ expires_at. На поверхности вроде работает. Но в то же время это приводит к тому, что расписание становится строгим. После того, как время выполнения пропущено expires_at, его невозможно выполнить повторно.
Это решение работает, если ваши задания допускают досрочное выполнение. Но, к сожалению, большинство запланированных заданий просто не позволяют этого.
Лучший подход — итерация
Интуиция? Вместо того, чтобы сохранять производное значение, более полезно и эффективно хранить значения, которые могут быть получены другими возможными значениями в любое время с помощью формулы.
Таким образом, действительно простой подход называется итерацией, это просто начальное значение, которое увеличивается/уменьшается с постоянным шагом, пока не будет достигнуто конечное значение.
Независимо от даты и времени истечения срока действия, есть преимущество в позднем выполнении задания, если оно выполняется после `next_run`.
Пример:
Проще говоря, указав, сколько раз должно выполняться периодическое расписание, то есть: 5. После 5-кратного выполнения задания оно завершается. Чтобы отслеживать ход выполнения задания, просто добавьте новое свойство число_выполнений.
entry = e(7 days, job); iteration = 5; For each 7 days, [1]: job(); // execution_count = 1 [2]: job(); // execution_count = 2 [3]: job(); // execution_count = 3 [4]: job(); // execution_count = 4 [5]: job(); // execution_count = 5
Необычный подход — итерационный цикл
Основываясь на этой основе, теперь немного оживим. Давайте введем новый параметр: цикл. В рамках итерации может быть n циклов, каждый из которых отличается d периодом/длительностью. Такой дизайн допускает реализацию на основе вех, где он сбрасывается после каждой итерации.
entry = e(7 days, job); // total executions = 2 * 2 iteration = 2; cycle = 2; // iteration 1 [1]: job(); // cycle 1 [2]: job(); // cycle 2 // iteration 2 [1]: job(); // cycle 1 [2]: job(); // cycle 2
Учитывая свойство: число_выполнений, нетрудно вывести такие значения, как: current_iterationиcurrent_cycle. Используйте арифметическую прогрессию, где a = 0, d = 1.
Let it be the progression of execution_count: a = 0 // initial value d = 1 // single job execution per schedule +1 +1 | | |---|---| ... 0 1 2
Давайте подведем итог, учитывая итерацию = 2, цикл = 2,
1. execution_condition = execution_count < iteration * cycle 2. current_iteration = Math.ceil(execution_count/cycle) 3. current_cycle = ((execution_count-1)%cycle) + 1 |-----------------------------------------------------| | execution_count | current_iteration | current_cycle | |-----------------------------------------------------| | 1 | 1 | 1 | | 2 | 1 | 2 | | 3 | 2 | 1 | | 4 | 2 | 2 | -------------------------------------------------------