この記事では、Fly.ioのcronを設定してRailsアプリのrakeタスクを定期実行する方法を解説します。
1. 開発環境
- Ruby:3.3.0
- Rails:7.1.2
- PostgreSQL:15.3
- MacBook Pro (13-inch, 2020)
- macOS Sonoma 14.2.1
2. 手順
2-1. サンプルアプリを作成
まずはサンプルアプリを作成します。ここではEventモデルを持つシンプルなアプリを作成します。
$ rails new flyio-cron-sample -d postgresql $ cd flyio-cron-sample $ bin/setup $ bin/rails s
ブラウザでRailsのデフォルト画面が表示されることを確認します。
次に、EventのCRUDをscaffoldで作成します。
$ bin/rails g scaffold Event title:string $ bin/rails db:migrate
ルートルーティングを変更します。
# config/routes.rb Rails.application.routes.draw do 省略 - # root "posts#index" + root "events#index" end
railsサーバーを起動して、ブラウザからEventのCRUDを確認します。
$ bin/rails s
2-2. rakeタスクを作成
次に、定期実行したい処理をrakeタスクとして作成します。
$ bin/rails g task delete_events
生成されたlib/tasks/delete_events.rake
を以下のように編集します。
# lib/tasks/delete_events.rake namespace :event do desc 'delete events' task delete_events: [:environment] do Event.destroy_all end end
ここでは、全てのEventを削除するタスクを実装しています。
次に、作成したrakeタスクが実行できることを確認していきます。
event作成後、以下のコマンドでrakeタスクを実行します。
$ bundle exec rake event:delete_events
eventが削除されていることが確認できました。
irb(main):006> Event.all Event Load (0.4ms) SELECT "events".* FROM "events" /* loading for pp */ LIMIT $1 [["LIMIT", 11]] => [] irb(main):007>
2-3. Fly.ioにデプロイ
Fly.ioにデプロイしていきます。
$ fly launch
Do you want to tweak these settings before proceeding?
でn
を選択して、デフォルトのスペックのままで作成します。
デプロイを実行します。
$ fly deploy $ fly apps open
ブラウザからアクセスして、デプロイされたアプリが動作していることを確認します。
2-4. cronの設定を追加
まずはcrontabを作成します。
$ touch ./crontab
crontab
を以下のように編集します。
+ 0 20 * * * bundle exec rake event:delete_events
上記の設定により、日本時間のAM5:00にrakeタスクが実行されます。
次にcronの設定を追加します。
Dockerfile
を以下のように編集します。
省略 # Copy built artifacts: gems, application COPY --from=build /usr/local/bundle /usr/local/bundle COPY --from=build /rails /rails +# Latest releases available at https://github.com/aptible/supercronic/releases +ENV SUPERCRONIC_URL=https://github.com/aptible/supercronic/releases/download/v0.2.29/supercronic-linux-amd64 \ + SUPERCRONIC=supercronic-linux-amd64 \ + SUPERCRONIC_SHA1SUM=cd48d45c4b10f3f0bfdd3a57d054cd05ac96812b + +RUN curl -fsSLO "$SUPERCRONIC_URL" \ + && echo "${SUPERCRONIC_SHA1SUM} ${SUPERCRONIC}" | sha1sum -c - \ + && chmod +x "$SUPERCRONIC" \ + && mv "$SUPERCRONIC" "/usr/local/bin/${SUPERCRONIC}" \ + && ln -s "/usr/local/bin/${SUPERCRONIC}" /usr/local/bin/supercronic + + # You might need to change this depending on where your crontab is located +COPY crontab crontab # Run and own only the runtime files as a non-root user for security RUN useradd rails --create-home --shell /bin/bash && \ chown -R rails:rails db log storage tmp USER rails:rails 省略
fly.toml
を以下のように編集します。
+[processes] + web = "bin/rails server" + cron = "supercronic /rails/crontab" [http_service] internal_port = 3000 force_https = true auto_stop_machines = true auto_start_machines = true min_machines_running = 0 - processes = ["app"] + processes = ["web"] -[checks] - [checks.status] - port = 3000 - type = "http" - interval = "10s" - timeout = "2s" - grace_period = "5s" - method = "GET" - path = "/up" - protocol = "http" - tls_skip_verify = false - [checks.status.headers] - X-Forwarded-Proto = "https" [[vm]] cpu_kind = "shared" cpus = 1
- Crontab with Supercronic - Setup a web & cron process
- デプロイ時にcronプロセスを実行するマシンのhealth checksでタイムアウトが発生するため、ここでは一時的に
checks
の項目を削除しています。
再度デプロイを行い、cronの設定を反映させます。
$ fly deploy
2-5. eventsテーブルにデータを追加
デプロイしたアプリにブラウザからアクセスし、eventを作成してdbを確認します。
以下のコマンドを実行してdbサーバに接続します。
$ fly postgres connect -a flyio-cron-sample-db
postgres=# \l List of databases Name | Owner | Encoding | Collate | Ctype | ICU Locale | Locale Provider | Access privileges ---------------+----------+----------+------------+------------+------------+-----------------+----------------------- flyio_cron_sample | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | postgres | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | repmgr | repmgr | UTF8 | en_US.utf8 | en_US.utf8 | | libc | template0 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | =c/postgres + | | | | | | | postgres=CTc/postgres template1 | postgres | UTF8 | en_US.utf8 | en_US.utf8 | | libc | =c/postgres + | | | | | | | postgres=CTc/postgres (5 rows)
postgres=# \c flyio_cron_sample You are now connected to database "flyio_cron_sample" as user "postgres". flyio_cron_sample=# \dt List of relations Schema | Name | Type | Owner --------+----------------------+-------+--------------- public | ar_internal_metadata | table | flyio_cron_sample public | events | table | flyio_cron_sample public | schema_migrations | table | flyio_cron_sample (3 rows) flyio_cron_sample=# SELECT * FROM events; id | title | created_at | updated_at ----+--------+----------------------------+---------------------------- 2 | event1 | 2024-01-12 12:36:02.324279 | 2024-01-12 12:36:02.324279 3 | event2 | 2024-01-12 12:36:09.853371 | 2024-01-12 12:36:09.853371 4 | event3 | 2024-01-12 12:36:18.770443 | 2024-01-12 12:36:18.770443 (3 rows)
eventが作成されていることを確認できました。
2-6. rakeタスクの定期実行を確認
crontab
に設定した時刻を過ぎたら、rakeタスクが実行されていることを確認します。
$ fly postgres connect -a flyio-cron-sample-db Connecting to fdaa:5:176b:a7b:22e:91d4:a985:2... complete psql (15.3 (Debian 15.3-1.pgdg120+1)) Type "help" for help. postgres=# \c flyio_cron_sample You are now connected to database "flyio_cron_sample" as user "postgres". flyio_cron_sample=# flyio_cron_sample=# flyio_cron_sample=# SELECT * FROM events; id | title | created_at | updated_at ----+-------+------------+------------ (0 rows) flyio_cron_sample=#
eventが削除されていることが確認できました。
2024-01-12T20:00:00.210 app[e7842302cd6278] nrt [info] time="2024-01-12T20:00:00Z" level=info msg=starting iteration=0 job.command="bundle exec rake event:delete_events" job.position=0 job.schedule="0 20 * * *" 2024-01-12T20:00:01.875 app[e7842302cd6278] nrt [info] time="2024-01-12T20:00:01Z" level=info msg="job succeeded" iteration=0 job.command="bundle exec rake event:delete_events" job.position=0 job.schedule="0 20 * * *"
cronプロセスを実行しているマシンのログからも、rakeタスクが実行されていることが確認できました。
【参考】