あまブログ

ドキドキ......ドキドキ2択クイ〜〜〜〜〜〜〜ズ!!

【Fly.io + Rails】cronでrakeタスクを定期実行する

この記事では、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

再度デプロイを行い、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タスクが実行されていることが確認できました。


【参考】