技術的雑談-Moodleの活動(Activity)プラグインのイベント処理時の注意
環境
- Moodle-1.9.6
- 活動(Activity)のプラグインを作成し、イベントハンドラを作る時
現象
- イベントハンドラ内で一旦エラーが起こると、後続のイベントが実行されないように見える
- イベントタイプ「cron」でディスパッチされたイベントがいつまでも実行されないように見える
原因 その1
Moodleのeventsの仕組みによるものです。
イベントハンドラメソッドの戻り値がtrue以外の場合、MoodleはそのイベントをDB上のテーブル「mdl_events_queue」と「mdl_events_queue_handlers」に保存し、後からcronを契機としてイベントの再実行を試みます。
DB上のイベントキューに「同一イベント名」かつ「同一イベントハンドラメソッド」のイベントがキューイングされている場合、そのイベントの設定がinstantであっても強制的にDB上にキューイングされます。
もしイベントハンドラメソッドがデータ不整合などの人為介入を必要とする状態でfalseを返し続ける場合、そのイベントは外見上新しいイベントを受け付けなくなっているように見えてしまいます。
よって、イベントハンドラメソッドの戻り値はDBやネットワークなどの一時的不通などによるリトライして成功する望みのある事象以外でfalseになってはいけない。
また、その時のDBの状態などに依存する処理を行っているイベントハンドラメソッドは戻り値にfalseを返してはならない。
対処 その1
あるイベントが実行されなくなってしまったように見えた場合、上記のテーブルの中を参照してキューにたまっているレコードを削除してやることによって次のイベントから元通りほぼリアルタイムで実行されるようになる。
もしくはMoodleのcron実行が正しく行われていないのかもしれない。
ちなみに、イベントのcron実行はcron.phpをブラウザから実行しても画面には何も表示されない!(不親切)
なので、イベント中の動作ログなどはファイルやDBなどに書き出しておかないと後からトラブルシューティングが困難になる。
原因 その2
moodle-1.9.xでは/lib/eventlib.php内にevents_cron()メソッドが用意されていて、一見cronでこのメソッドを呼んでくれそうな感じがしますが、実際は誰も呼んでいません!!!
なので、一旦キューイングされて即時処理されなかったイベント(即時実行でエラーとなったイベントを含む)はそのままでは永遠に実行されません。
対処 その2
moodle-1.9.xではmoodleのルートディレクトリ直下の「/local/cron.php」が本来のcron処理の最後に呼び出されます。
(あくまでも設置手順に従ってmoodle用のcronの設定をしてあればですが…。)
なので、<moodle_root>/local/cron.php というディレクトリをファイルを作成し、中身に以下のようなものを書いておけばとりあえず滞留したイベントを再実行しようとしてくれるはずです。
<?php require_once($CFG->libdir.'/eventslib.php'); events_cron();
※ config.phpなどの必須requireは本来のcron.phpで行われているので、/local/cron.phpでは行わなくても大丈夫そうです。
尚、URL直接指定による不正アクセスに対処する為に、/localディレクトリには.htaccessファイルで直接アクセスを禁止する設定をしておいた方がよいかと思われます。
(ってか、_cron()メソッド作っておきながらそれを叩く仕組みを実装していないって…何なの??)
履歴
- 2009/12/18 -- 初版
- 2010/03/12 -- 問題その2の部分を追記
技術的雑談へ戻る