シンプルなPHPタスクスケジューラ

画像

多かれ少なかれ大規模なプロジェクトの進化の過程で、スケジュールされたタスク(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分だった場合)、アクションが数回実行されることにも注意してください。 つまり、グループ化されません。


おそらくそれだけです。 ライブラリは本当に小さいですが、誰かに役立つことを願っています。
建設的な批判と開発援助は大歓迎です。


Github
パカギスト



Source: https://habr.com/ru/post/J345802/


All Articles