多かれ少なかれ大規模なプロジェクトの進化の過程で、スケジュールされたタスク(cronジョブ)の数が非常に多くなり、サポートがdevopsにとって悪夢になるような状況が発生する場合があります。 この問題を解決するために、PHPでスケジューラー実装を作成し、それをプロジェクトの一部にし、タスク自体-その構成の一部にするというアイデアに思いつきました。 この場合、必要かつ十分なcronジョブの数は1に等しくなります。
しばらく前に、偶然イベント企画のためのモジュールを開発しました。 アプリケーションのユーザー向けのある種の単純化された類似性Google / Appleカレンダー。 繰り返しイベントの日付とルールを保存するために、iCalendar形式( RFC 5545 )を使用することが決定されました。これは、曜日、月、繰り返し数などを考慮したイベントの繰り返しスケジュールの1行の記述を可能にします。 いくつかの例:
FREQ=WEEKLY;BYDAY=SU,WE
毎週土曜日と水曜日
FREQ=MONTHLY;COUNT=5
毎月5回
FREQ=YEARLY;INTERVAL=2;BYMONTH=1;BYDAY=SU
- FREQ=YEARLY;INTERVAL=2;BYMONTH=1;BYDAY=SU
、1月の毎週土曜日
ご覧のとおり、この標準を使用すると、cronが提案するよりもはるかに柔軟にイベントを繰り返すためのルールを記述できます。
iCalendar形式で作業するための素晴らしいライブラリが見つかりました(スターを後悔しないでください):
https://github.com/simshaun/recurr
RRULE(繰り返しルール)を操作するためのツールがあるので、問題は小さいままです。 タスク(PHP callable
タイプの明示)を計画および実行できるクラスをいくつか作成します。
ライブラリのインストール:
composer require hutnikau/job-scheduler
タスクのスケジューリングと起動:
\Scheduler\Job\Job
-タスクを表すクラス
インスタンスを作成するには、その繰り返しルール(RRULE)とcallable
タイプのインスタンスが必要です。
$startTime = new \DateTime('2017-12-12 20:00:00'); $rule = new \Scheduler\Job\RRule('FREQ=MONTHLY;COUNT=5', $startTime); //run monthly, at 20:00:00 starting from the 12th of December 2017, 5 times $job = new \Scheduler\Job\Job($rule, function () { //do something });
別の方法は、 \Scheduler\Job\Job::createFromString()
を使用することです。
$job = \Scheduler\Job\Job::createFromString( 'FREQ=MONTHLY;COUNT=5', //Recurrence rule '2017-12-28T21:00:00', //Start date function() {}, //Callback 'Europe/Minsk' //Timezone. If $timezone is omitted, the current timezone will be used );
タイムゾーンを忘れないでください。 不愉快な驚きを避けるために、これらを常に明示的に指定することを強くお勧めします(このライブラリで作業するときだけでなく、一般的に\DateTime
でも)。
タスクをスケジューラに追加します。
$scheduler = new \Scheduler\Scheduler() $scheduler->addJob($job);
タスクの配列をコンストラクターに渡すこともできます。
$scheduler = new \Scheduler\Scheduler([ $job, //more jobs here ])
スケジュールされたタスクを実行します。
$jobRunner = new \Scheduler\JobRunner\JobRunner(); $from = new \DateTime('2017-12-12 20:00:00'); $to = new \DateTime('2017-12-12 20:10:00'); $reports = $jobRunner->run($scheduler, $from, $to, true);
この例では、指定された期間(10分)にスケジュールされたすべてのタスクが完了します。 したがって、 JobRunner
実行するcronジョブは1つだけ必要JobRunner
。
$to
パラメータを省略すると、 $to
現在$from
すべてのタスクが実行されます。
最後のパラメーターは、実行時間が境界値(上記の例の「2017-12-12 20:00:00」および「2017-12-12 20:10:00」)に正確に一致するタスクを完了するかどうかを決定します。
cronを使用してスケジューラーを開始する場合、cronの精度は理想的ではないため、最後の開始時間を保存し、次の開始時に$from
パラメーターに渡すことをお勧めします。タスクをスキップしたり、2回実行したりすることができます。
$jobRunner->run(...)
は、完了したタスクの結果の配列(タイプ\Scheduler\Action\Report
のオブジェクトの配列$jobRunner->run(...)
返します。
\Scheduler\Action\Report { /* Methods */ public mixed getReport ( void ) public Action getAction ( void ) public string getType ( void ) }
\Scheduler\Action\Report::getReport()
呼び出すことにより、呼び出し可能な結果(それによって返される値\Scheduler\Action\Report::getReport()
を取得できます。
タスクの実行中に例外がスローされた場合、 \Scheduler\Action\Report::getReport()
は同じ例外を返します。
\Scheduler\Action\Report::getAction()
は、実行されたアクションを記述する\Scheduler\Action\ActionInterface
インスタンスを返します。 これを使用すると、アクションの実行時間を確認したり、アクション自体を取得したりできます(ジョブ)。
また、スケジュールされたタスクが複数回実行される場合(たとえば、RRULEでMINUTELY間隔が使用され、 MINUTELY
$to
渡される$from
と$to
toのJobRunner
10分だった場合)、アクションが数回実行されることにも注意してください。 つまり、グループ化されません。
おそらくそれだけです。 ライブラリは本当に小さいですが、誰かに役立つことを願っています。
建設的な批判と開発援助は大歓迎です。