スリ飯屋MaLankaのフリーエンジニアな日々

このブログでは、フリーランス5期目となる自身の実体験から、フリーランスエンジニアになるためのノウハウ、ブログや沖縄移住、スリランカの最新情報について発信します。

【Heroku無料廃止】Railway.appでWheneverを使わずHeroku Schedulerのように定期処理を実行する

※記事内に提携先企業のアフィリエイト広告(リンク、バナー等)、Google広告を含む場合があります

RailwayでWheneverを使わずHeroku Schedulerのように定期処理を実行する


こんにちは、現役沖縄フリーランスエンジニアのmahです。


このブログでは、

僕がIT未経験から約1年でフリーランスエンジニアになるまでの過程、

ノウハウなどを書いていきます。


今回は、


  • Railway.appでWheneverを使わずHeroku Schedulerのように定期処理を実行する


についてです。


【Heroku無料廃止】Railway.appでWheneverを使わずHeroku Schedulerのように定期処理を実行する



背景


HerokuからRailway.appに移行するため、

gem Whenever を使ってcron設定をしていましたが、

設定したrakeタスクが動かない。


以下、

Railway.appで設定しているビルド時、ビルド完了後に実行するコマンド。


  • Build Command
$ mkdir -p tmp/pids && sudo apt-get -y update && sudo apt-get -y upgrade && sudo apt-get -y install cron
  • Start Command
 $ sudo cron && sudo service cron restart && bundle exec whenever --set environment=production --update-crontab && crontab -l && bundle exec puma -C config/puma.rb


Railway.appに出ているログは下記。


  • Deploy Logs
restarting periodic command scheduler: cronStopping periodic command scheduler: cron.

Starting periodic command scheduler: cron.

task1

task2

[write] crontab file updated

# Begin Whenever generated tasks for: /app/config/schedule.rb at: 2022-09-18 00:49:52 +0000

2 * * * * /bin/bash -l -c 'cd /app && RAILS_ENV=production bundle exec rake task1 --silent >> log/cron_log.log 2>&1'

*/1 * * * * /bin/bash -l -c 'cd /app && RAILS_ENV=production bundle exec rake task2--silent >> log/cron_log.log 2>&1'

# End Whenever generated tasks for: /app/config/schedule.rb at: 2022-09-18 00:49:52 +0000
[1] Puma starting in cluster mode...
[1] * Version 4.3.12 (ruby 2.6.7-p197), codename: Mysterious Traveller
[1] * Min threads: 5, max threads: 5
[1] * Environment: production
[1] * Process workers: 1
[1] * Phased restart available
[1] * Listening on tcp://0.0.0.0:6535
[1] Use Ctrl-C to stop
[1] - Worker 0 (pid: 194) booted, phase: 0
[1] - Gracefully shutting down workers...


ローカルで検証している時はこれで各rakeタスクがスケジュール毎に実行されるのですが、

Railway.appの環境だと実行されません。


Wheneverのcron設定ファイルやRailway.app側の実行コマンドを変えて検証していましたが、

なかなか終わらないので発想を変えます。


rakeタスクを実行するエンドポイントを作り、

そこにNew Relicから一定時間毎にpingを送るようにすることで、

実質Herokuスケジューラと同様の挙動をさせました。


これでWheneverを使わずHeroku Schedulerのような定期処理が可能です。


手順


1. ping先のルーティング定義


何でも良いですが、

今回は /ping_tasks/タスク名 というURLにpingでリクエストされたらrakeタスクを実行するようにします。

# config/routes.rb
  resources :ping_tasks, only: :none do
    collection do
      get :task1 # GET /ping_tasks/task1
      get :task2 # GET /ping_tasks/task2
    end
  end


2. コントローラ作成


/ping_tasks/タスク名 というルーティングに倣って ping_tasks_controller というコントローラを作成します。

# app/controllers/ping_tasks_controller.rb

class PingTasksController < ApplicationController
end


3. rakeタスク毎にアクション定義


rakeタスク毎の名前でアクションを作成します。

# app/controllers/ping_tasks_controller.rb
class PingTasksController < ApplicationController
  def task1
    `RAILS_ENV=#{Rails.env} bundle exec rake task1 --trace`

    head :no_content
  end

  def task2
    `RAILS_ENV=#{Rails.env} bundle exec rake task2 --trace`

    head :no_content
  end

  def health_check
    `RAILS_ENV=#{Rails.env} bundle exec rake health_check --trace`

    head :no_content
  end
end


4. New Relicからpingの設定


New Relicからpingを送る設定をします。


まずNew Relicで新規登録してログインしたら、

左サイドバーの synthetic monitoring 選択し、

右上にある create monitor をクリック。

new relic synthetic monitoring create monitor モニター作成.jpg


次に ping を選択。

new relic synthetic monitoring ping availavility.jpg


続いてmonitorの名称、ping先のURL、時間間隔などを入力します。

new relic synthetic monitoring create monitor モニター設定.jpg


最後にlocationの設定。

new relic synthetic monitoring create monitor select lotations.jpg

済んだら save monitor をクリックして作成完了。


run check を実行して成功していたら、

Railway.app側のログをチェックしてrakeタスクが実行されていればOKです。

new relic synthetic monitoring run check.jpg


5. New Relicのリクエストの場合のみ実行するように簡易なバリデーションをつける


パラメータに new_relic='true' がある時だけ実行するようにします。


New Reric側のpingURLの末尾に ?new_relic=true を付けます。


コントローラーにコードを追加します。

class PingTasksController < ApplicationController
  before_action :from_new_relic? <= 追加

  def task1
    `RAILS_ENV=#{Rails.env} bundle exec rake task1 --trace`

    head :no_content
  end

  def task2
    `RAILS_ENV=#{Rails.env} bundle exec rake task2 --trace`

    head :no_content
  end

  def health_check
    `RAILS_ENV=#{Rails.env} bundle exec rake health_check --trace`

    head :no_content
  end

  private <= 追加

  def from_new_relic? <= 追加
    return head :no_content if params[:new_relic].blank? || params[:new_relic].to_s != 'true'
  end
end


この状態で、

リクエストしたパスが /ping_tasks/task1/ping_tasks/task1?new_relic= の時にはtask1は実行されず、

/ping_tasks/task1?new_relic=true の時にのみ task1 が実行されていればOK。


以上です。