2017.11.8
Livvon#27【ローカルサーバーでcronキュー】
はあ・・・・・・本来は先月末までにはβ版が完成するはずだったのに未だプロトタイプのリファインすら終わっていない・・・・・・なんでなんだろうなあ。
僕だってほんとは一刻も早く公開したいんですけど、β版の目標としては
最低限「使える」ものでなくてはいけないので、あーこのアラートの出し方が気になる、とか、エラー処理ちゃんと書かないと・・・・・・とかいう加筆修正してたら時間ばっか取られるんですよね。
さっきもクッキーがバグったことによるバグで1時間ほど溶かされたしな 分かるかよそんなん
今日のテーマとしてはcronです。
cronっていうのは、まぁPHPの自動実行なんですけど、この仕組自体はtwitterの日記告知スクリプトで既に使ってます。
そんな感じの技術をローカルで使えるようにして、本番環境でのcronを擬似的に実装してみよう、ということになりますね。ローカルサーバーにはcronを実行できるものがないようで。一応こねくり回せばできるようですが、バッチを用意した方が楽なので素直にバッチファイルにて実行します。
そもそも、なんでcronを採用するかっていうと
キューを実装したいの一言に尽きます。
例えばメール送信とか、サーバーの応答時間が長くて鬱陶しいなぁって思ってるんで、そこをカットしたいなぁと思うと非同期にする他ありません。
ただページ遷移を伴うような処理はjavascriptでは書けませんし、だったら送信が完了しましたって体でページ遷移させて、実際のメール送信はキューでやるというのがベターかなとも思います。将来的な負荷分散もできますしね。1分間に送るメールは何通が限度、みたいな。
具体的なキューの実装方法に関しては考慮すべきところがたくさんありますけどね。送信元と送信先のアドレスは格納するとして、メール本文はどうしようかという話があります。
平文としてDBに直接ぶっ込んでしまうか、必要な情報をシリアライズでもして格納するか、あるいは予約情報自体はDBに格納されているのでそこから情報を引っ張ってくるか・・・・・・まぁこっちの方が良さそうではありますけどね。
平文として保存するとメール送信のメソッドを1つ準備するだけで終わるんで非常に楽なんですが、デバッグしづらそうだし、そもそも美しくないというか、
なんか臭うんですよね・・・・・・笑
まぁこれはβ版ではめんどくさいので実装しませんけど(笑)、ハンドシェイクの自動拒否はさすがに実装しないとマズいですね。
とはいえ、処理内容としては簡単で、1分に1回走らせて、デッドラインを越えたヤツがいたらメール送信しDBを書き換えるって感じですかね。
このメール送信の部分がまたボトルネックになりそーな気もしなくもないですが、まぁなるようになると信じなくてはなりません。僕は技術者じゃないし、技術者になるつもりも本当はないのだ。向いてないから(笑)
良いシステムを作れば良いエンジニアに巡り会えると信じるしかないですね。もっと経験のある人に作り直してもらいたいのだ。笑
ローカルサーバー上でcronを走らせる方法はいくつかありますが、最も簡単なのはLaravelに組み込まれている機能を使うことですね。
Laravelの機能そのものを使うことで、本番環境でも同じコマンドでcronを走らせることができます。うわーめっちゃ便利。
とりあえずWindowsの方では、タスクスケジューラーでしたっけ、あれを使いまして・・・・・・
確かこんな感じのコマンドを動かすようにすれば良いかなって感じです。いまはmacの方で書いてるので後述...
つまりまだ動かせていないんですね
あ、でですね。肝心のコードですけど。
protected function schedule(Schedule $schedule)
{
$schedule->call(function () {
$queue = (new T_reservationsDAO())
->where_waiting()//is_acceptがnullのもの
->where_expire()//デッドラインを越えているもの
->select_email()
->select_data()
->get();//未処理で期限が切れているハンドシェイクデータを取得
if(empty($queue)){return;}//データがなければおわり
(new HandshakeController())->deny_by_deadline($queue);
return true;
})->cron('* * * * * *')
->name("handshake_check")
->withoutOverlapping();
}
Livvonの実装としてはこんな感じです。最初は別ファイルでやってたんですが、なんかうまくいかなかったんでとりあえず最初はクロージャで。
こういうcronでの自動処理はおそらくRC版では酷使する予定なので、使い方には慣れておくべきなんですけど、デバッグが割とやりづらい感じでしたゆえ・・・・・・。
まぁそんな難しい書き方はしていないんですが、nameの部分がないと怒られます。あと、その後のwithoutOverlappingは多重起動防止ですね。こーいうのあるとやりやすくて良きですね。
macでやると、なんか
No such file or directoryとかいう意味わかんないエラーが出てきてハマっちゃいました。
最初はログファイルの話で、無理矢理フォルダを作ったら解決したんですが、次はSQLでも同じエラーがでてきちゃいましてね。
SQLでNo such file or directoryってなんやねんwwwwwって思ったんですが、調べたところターミナル上から接続する場合にはまた別に設定をしなくてはいけないみたいですね。
やることとしては、まずMySQL上で
show variables like '%sock%'を実行します。
するとこんな感じの結果が得られるので、この中のsocketのパスをコピーして、database.phpに追記します。
'mysql' => [
'driver' => 'mysql',
'host' => env('DB_HOST', '127.0.0.1'),
'port' => env('DB_PORT', '3306'),
'database' => env('DB_DATABASE', 'forge'),
'username' => env('DB_USERNAME', 'forge'),
'password' => env('DB_PASSWORD', ''),
'unix_socket' => env('DB_SOCKET', ''),
'charset' => 'utf8mb4',
'collation' => 'utf8mb4_unicode_ci',
'prefix' => '',
'strict' => true,
'engine' => null,
'unix_socket' => '/Applications/XAMPP/xamppfiles/var/mysql/mysql.sock',//←これね
],
これでエラーが消えましたので、実行自体はできるようになったと思います。
後はcrontabに追記すれば良さそうですね。
crontab -e
(vimに入る)
* * * * * php /Users/a/Documents/TheRong\'sCaravan/php/Livvon/artisan schedule:run
|
ここでも結構ハマりましたが、僕の環境だとこんな感じのパスになります。ようするに、プロジェクトルートまでの絶対パスを指定して、その後にartisanを追加するのが肝になりますね。
ユーザー名を「a」にしているやる気の無さがバレてしまいますね(笑)(笑)(笑)
無事にローカル側にメールが届き、スケジュールが走りましたって感じの表示が出ればいいと思います。めでたしめでたし。
なんかエラーが見たかったら、同じようにローカルメールで配信されると思われます。
メールの自動送信は上手くできましたので、後は似たような流れでキャンセルを実装すればよき、かな・・・・・・?
せっかくなのでキャンセル部分に関してはキューで実装してみることにしますか。つまり、メール送信といった重い機能は、ユーザーの方では応対を待つのではなく、1分ごとに実行されるこのcronでメール送信を担う、という方針でいくべきですね。