メドピア開発者ブログ

集合知により医療を再発明しようと邁進しているヘルステックカンパニーのエンジニアブログです。読者に有用な情報発信ができるよう心がけたいので応援のほどよろしくお願いします。

ClinPeer Maintenance Tasks Gemの活用事例

こんにちは!
サーバーサイドエンジニアの伏見です。

弊社で新しくリリースした「ClinPeer」の裏側連載。

tech.medpeer.co.jp

この記事では、サーバーサイドで導入したGem Maintenance Tasks について書いていきます。

導入のモチベーション

開発初期や今後の運用の中で、データマイグレーション*1を考える場面が多くなるだろうという考えがありました。
Rails ConsoleやRake Taskで運用することがあるかと思いますが*2、以下のような懸念がありました。

  • 本番環境のサーバーにアクセスをして実行することが必要になる、実行の権限管理の問題が生じる
  • コンソールでの手動操作になるため、誤操作のリスクがある
  • 同期的にJobが実行されるため、コネクションが切れるなどのリスクがある
  • 実行した履歴が追いづらい

このような課題に対して、Maintenance Tasks はそれらを解決の見込みがあるのではとなりました。

  • 実行権限をサービスの管理画面のアカウント権限に寄せることができる
    • 本番サーバーへのアクセス権限と比べて、権限を委譲するのが容易になる
  • 専用のダッシュボードがある
    • 100%防げるわけではないが、実行するコードが画面に表示されたり、実行の確認がCUI操作より容易である
    • 作成されているタスク以外の操作が画面上からはできないため、誤操作を減らせるという利点がある
    • 実行状況や、履歴を見ることができる
  • Jobの実行が非同期である
    • Maintenance Tasks はActive Job に依存してJobが実行される

社内の別サービスですでにMaintenance Tasksを導入して運用している事例もあり、ClinPeer でもMaintenance Tasks の導入に至りました。

ディレクトリ構成

Maintanance Tasks のタスクファイル自体は以下のディレクトリに配置していました。

app/tasks/maintenance
├─ [namespace] # 運用で継続して実行が見込まれるタスクを、namespaceを切って格納する
└─ one_shot # 単発で実行後、削除を予定しているタスク

基本的にはMaintanance Tasks のgenerate コマンドで生成される構成に寄りつつ、継続で実行することが見込まれるものと、そうでないものでディレクトリを分けるという運用を行なっておりました。

metadataの設定

Maintenance Tasksは実行ごとにmetadataという形で追加の情報を付与することができます。*3
ClinPeerでは、taskを実行したユーザーのIDをmetadataとして渡すようにしています。

MaintenanceTasks.metadata = lambda {
  # 本来Admin名前空間以外からはCurrentオブジェクトを参照できないようにしているがここは例外的に許容する。
  { user_id: Admin::Current.user&.id }
}

こちらによって、ダッシュボード上で実行されたタスクを見た時に、誰が操作を行ったのかが分かりやすくなります。

callbackの設定

Maintenance Tasksでは実行中のライフサイクルごとに、callbackを設定することができます。*4
ClinPeerではcallbackを利用して、実行状態のslack通知を行っていました。

公式ドキュメントではタスクファイルに設定を記述する方法を紹介をされていますが、共通の設定にするため、metadataと同様initializersに記載しています。

Rails.autoloaders.main.on_load("MaintenanceTasks::Task") do
  MaintenanceTasks::Task.class_eval do
    %i[start pause cancel complete error].each do |event|
      public_send(:"after_#{event}") { notify(event) }
    end

    private

    def notify(event)
      SendSlackJob.perform_later # Slackに通知を送信する処理、詳細は省略
    end
  end
end

Error Reporter

ここからは小ネタです。

Rails にはエラー発生時の処理をまとめるために、Error Reporter という仕組みが提供されています。 (Error Reporter については、後日紹介記事が書かれる予定なので、詳細についてはご期待ください)
(三村追記)紹介記事書きました! tech.medpeer.co.jp

Maintenance Tasks は、Jobのエラー発生時、Error Reporter でエラー情報が送信されるようになりました。
Error Reporter をすでに利用しているサービスであれば、エラーハンドリング周りの処理を書く必要が無くなります。

github.com

ClinPeerでも元々Error Reporter を使用していて、自前でエラーハンドリング周りの処理を記載していましたが、このアップデート以降は自前で書いていた処理を削除することができました。

Maintenance Tasks とSolid Queue の併用

Maintenance Tasks で使用されているGemに job-iterationがあります。
このGem はJob の中断や再開を可能にするActiveJob の拡張機能です。
ClinPeer でMaintenance Tasks を導入した際、job-iteration がSolid Queue のサポートが不十分だったため、TERM シグナルの受信する処理を自前で記載しておりました。
こちらも、Solid Queue 公式でサポートされ、プロセス停止時に差し込めるフックが追加されています。

github.com

github.com

終わりに

ClinPeer でのMaintenance Tasks の利用にあたってのtips や小ネタを紹介してきました。
開発開始から早い段階で導入し、リリース後の現在も引き続き利用していますが特に大きな問題もなく現在は利用することができています。
ぜひ同じような課題感を感じていたら、利用を検討してみてください。


是非読者になってください!


メドピアでは一緒に働く仲間を募集しています。
ご応募をお待ちしております!

■募集ポジションはこちら medpeer.co.jp

■エンジニア紹介ページはこちら engineer.medpeer.co.jp

■メドピア公式YouTube  www.youtube.com

■メドピア公式note
style.medpeer.co.jp

*1:ここでのデータマイグレーションは、データそのものの移行、変更に焦点を当てています。

*2:https://speakerdeck.com/ohbarye/data-migration-on-rails で詳しく話されています

*3:https://github.com/Shopify/maintenance_tasks?tab=readme-ov-file#metadata

*4:https://github.com/Shopify/maintenance_tasks?tab=readme-ov-file#using-task-callbacks