【LINE通知機能】Docker+Redis+Sidekiq+Active Jobを使い設定時間にチャットが送信される処理を行う(ローカル)
はじめに
こんにちは! プログラミング初学者のyukimuraです!
今回は私自身の個人開発したアプリで実装した、LINE通知機能について記述しています
間違いなどありましたら、優しくご指摘いただけましたら幸いです
個人開発アプリ
GithubURL実装手順について
- LINE Developersでチャネルを作成する(公式アカウントの作成)
- 一度、ターミナルからの操作でメッセージが送れるようにする
- RedisをDockerコンテナに導入する
- SidekiqをDockerコンテナに導入する
- Active Jobを導入する
- 指定した時間にメッセージが送られる
環境
- docker
- rails 7.0.8.4
- ruby 3.2.3
- tailwind
- Render.com (デプロイ先)
Redisについて
Redisはデーターベースです。RDBMS(Relational database management system)とは違う仕組みで、高速にデータを処理することができる、という特徴などがあります。
今回の実装では、ジョブを永続的に保存するために使用します
詳しい解説は下記記事が非常に参考になりました
Sidekiqについて
Sidekiqは、Ruby on Railsなどのウェブアプリケーションでよく使われる「バックグラウンドジョブ」を処理するためのツールです。
Sidekiqの役割
Sidekiqはこのバックグラウンドジョブを効率よく処理する役割を持っています。例えば、ユーザーがサインアップしたときに確認メールを送るような処理を、Sidekiqがアプリとは別に裏で行います。これにより、アプリはユーザーにすぐに反応できるようになり、時間がかかる処理は後で自動的に進められます。
今回はRedisで溜まっているジョブを取り出してくれる役割で使用します
Active Jobについて
Active Job(アクティブジョブ)は、Railsアプリケーションで使われる「バックグラウンドジョブ」を簡単に管理できる機能です。
バックグラウンドジョブとは?
通常、ウェブアプリはユーザーのリクエストにすぐに応答しますが、例えばメールを送ったり、画像を処理したりするような作業は時間がかかることがあります。そうした作業をその場でやると、アプリが遅くなってしまいます。そこで、これらの時間がかかる作業を「バックグラウンドジョブ」として、アプリとは別に後で実行するようにします。
Active Job自体は、バックグラウンドでジョブを実行するための仕組みを提供しますが、ジョブの保存(キューイング)や管理は行いません。
まとめ
1. Active Jobでジョブを定義
Active Jobを使って、例えば「メールを送る」というジョブを定義します。この段階では、どのバックエンドを使ってジョブを処理するかは決まっていません。
2. ジョブのキューイング
定義されたジョブをバックエンド(Sidekiqなど)に渡します。バックエンドは、このジョブを「キュー」というリストに保存します。Redisは、この「キュー」を管理するために使われます。
3. ジョブの実行
Sidekiqなどのバックエンドが、Redisに保存されたジョブを順番に取り出し、実行します。Redisは非常に速いデータベースなので、このジョブのキューイングと取り出しが効率的に行えます。
こちらの記事の例えが個人的にわかりやすかったです
言うなれば、Active Jobは洗濯物をホイホイ洗濯かごに投げ込んでいるだけの人で、洗濯かごを管理する人(Redis)、洗濯かごから洗濯物をとって洗濯機を回す人(Sidekiq)も必要ということです。
LINE Developersでチャネルを作成する(公式アカウントの作成)
1. 実装を始めていきます
まずは~LINE Developersのコンソールでチャネルを設定~して、アプリの公式アカウントを作成してください
2024/9/4以降からチャネルの設定方法が変わりました
公式ドキュメントを参考に作成をしてください
2. 友達追加ボタンを実装する
-
チャネルの作成が完了したら、下記画像部分の
LINE Official Account Manager
にアクセスしてください
-
アクセスすると友達追加用のコードが発行されるので、それをコピーして任意のviewに貼り付けでボタンの実装は完了です
例
ターミナルからの操作でメッセージを送る
1. gem 'line-bot-api'のインストール
Gemfile
gem 'line-bot-api'
2. bundle install
bundle install
3. credentialsファイルにチャネルのトークンなどを記録する
下記コマンドをコンテナ内で実行してvimで操作します
EDITOR="vim" bin/rails credentials:edit
矢印キーでカーソルを操作し、任意の箇所でi
を押すと挿入モードに切り替わります。
line_notify:
chanel_id: YOUR_ID ## チャネルID
chanel_secret: YOUR_SECRET ## チャネルシークレット
chanel_taken: YOUR_TAKEN ## チャネルアクセストークン(長期)
を入力した上でescキー
で挿入モードを終えたのち、:wq
そしてEnter
を押せば保存完了です。
4. config/initialize/line_bot.rbを作成する
- config/initialize/line_bot.rbを作成して、LINE Botを使うために必要な「初期設定(初期化)」を行います。設定した3つを
Rails.application.credentials
から取り出して設定することで、このアプリがLINE Botとして認証され、LINEとやり取りができるようになります。
require 'line/bot'
LINE_NOTIFY_CLIENT = Line::Bot::Client.new { |config|
config.channel_id = Rails.application.credentials.dig(:line_notify, :channel_id)
config.channel_secret = Rails.application.credentials.dig(:line_notify, :channel_secret)
config.channel_token = Rails.application.credentials.dig(:line_notify, :channel_access_token)
}
5. app/service/notification_service.rbを新規で作成してpushメッセージを設定する
class NotificationService
def self.call
new.call
end
def call
send_push_message
end
private
def send_push_message
message = {
type: 'text',
text: 'これはPushメッセージです。'
}
response = LINE_NOTIFY_CLIENT.broadcast(message)
Rails.logger.info "Push message response: #{response.inspect}"
end
end
- app/serviceディレクトリは、Railsアプリケーションでビジネスロジックを整理するために使われます。簡単に言うと、「複雑な処理や共通する処理を1つのクラスやモジュールにまとめる場所」です。
外部サービスとのやり取りをまとめたクラスを作成し、APIへのリクエストを整理することもできます。
https://qiita.com/game4967/items/6592697777669b91d4fd
6. メッセージが送られるかを確認する
rails console
をターミナルで実行して
> NotificationService.call
上記コマンドを打った時に友達追加したLINEアカウントからメッセージが送信されているかを確認してください
RedisとSidekiqをDockerコンテナに導入する
1. compose.ymlにredisとsidekiqを追加します
redis:
image: "redis:7.0-alpine"
volumes:
- redis_volume:/data
command: redis-server --appendonly yes
ports:
- "6379:6379"
sidekiq:
build:
context: .
command: bundle exec sidekiq
volumes:
- .:/myapp
depends_on:
- db
- redis
2. volumes:にもredis_volume:を追加します。
volumes:
redis_volume:
参考記事
3. docker compose buildコマンドで再ビルドします
4. gem sidekiqとsideliq-schedulerを導入する
Gemfile
gem 'sidekiq'
gem 'sidekiq-scheduler'
5. bundle install
bundle install
sidekiq-cronとsidekiq-schedulerの違いについて説明
共通点
- 目的: 両方ともSidekiqジョブのスケジューリングを行うためのgemです。
- 機能: 定期的に実行するジョブを設定するための機能を提供します。
sidekiq-cron
-
Cron形式のスケジュール:
-
特徴:
sidekiq-cron
は、UNIXのcron形式のスケジュールを使用してジョブを定義します。これにより、非常に柔軟かつ詳細なスケジューリングが可能です。 - 使い方: cron形式のスケジュールを設定ファイルに記述し、その通りにジョブが実行されます。
-
例:
# config/sidekiq.yml :schedule: send_random_scam_push_message: cron: "0 7 * * *" # 毎朝7時に実行 class: "SendRandomScamPushMessageJob"
-
特徴:
-
依存関係:
-
依存:
rufus-scheduler
を内部で使用しています。 - 設定: Cron形式に慣れている人にとって使いやすい。
-
依存:
-
柔軟性:
- 高い: 非常に細かい時間指定が可能で、複雑なスケジュールを設定するのに適しています。
sidekiq-scheduler
-
シンプルなスケジュール形式:
-
特徴:
sidekiq-scheduler
は、YAML形式でシンプルにスケジュールを定義できます。人間が読みやすい形式でスケジュールを設定できるため、使い勝手が良いです。 - 使い方: YAML形式のスケジュールを設定ファイルに記述し、その通りにジョブが実行されます。
-
例:
# config/sidekiq_scheduler.yml send_random_scam_push_message: every: '1h' # 毎時実行 class: 'SendRandomScamPushMessageJob'
-
特徴:
-
依存関係:
-
独自:
rufus-scheduler
を使用せず、独自のスケジューリングロジックを使用します。 - 設定: よりシンプルで直感的な設定が可能です。
-
独自:
-
柔軟性:
- 中程度: Cron形式ほどの細かい設定はできませんが、頻度ベースのスケジューリングには十分対応できます。
どちらを選ぶべきか?
-
複雑なスケジュールが必要な場合:
-
sidekiq-cron
を選ぶと良いでしょう。Cron形式のスケジュールを使用することで、柔軟かつ詳細なスケジューリングが可能です。
-
-
シンプルなスケジュールが必要な場合:
-
sidekiq-scheduler
を選ぶと良いでしょう。YAML形式で簡単にスケジュールを設定できるため、使いやすさが魅力です。
-
まとめ
- sidekiq-cron: UNIXのcron形式を使用して詳細なスケジュール設定が可能。複雑なスケジュールに適している。
- sidekiq-scheduler: YAML形式でシンプルにスケジュール設定が可能。シンプルなスケジュールに適している。
それぞれの用途に応じて適切なgemを選択してください。
6. config/application.rbに下記を追加
class Application < Rails::Application
# 〜〜省略〜〜
config.active_job.queue_adapter = :sidekiq
# 〜〜省略〜〜
end
Railsアプリケーションでバックグラウンドジョブを処理するために、Sidekiqを使うように指定します。具体的には、Active Jobのジョブを実行する際の「キューアダプタ」をSidekiqに設定しています。
7. config/initializers/sidekiq.rbを作成し、下記のように記載。
Sidekiq.configure_server do |config|
config.redis = { url: 'redis://redis:6379' }
end
Sidekiq.configure_client do |config|
config.redis = { url: 'redis://redis:6379' }
end
Sidekiqのサーバー(ジョブを処理する部分)とクライアント(ジョブをキューに追加する部分)が、どちらも同じRedisサーバーに接続してデータをやり取りするように設定します
8. config/sidekiq.ymlを作成し、下記のように記載
:concurrency: 3
:queues:
- default
9. 導入の確認
別ターミナルで
docker compose exec web bundle exec sidekiq
を実行して、下記のように起動されれば導入完了
Active Jobを設定する
1. jobファイルを作成する
bin/rails g job send_line_message
下記コードを記述してください
class SendLineMessageJob < ApplicationJob
queue_as :default
sidekiq_options retry: 1
# Sidekiqはジョブの実行に失敗した場合、デフォルトで25回リトライするため、
# 何度も通知が送られないよう、リトライ回数を1回に指定
sidekiq_retry_in do |_count|
60
end
# ジョブのリトライ間隔を60秒に設定
def perform
NotificationService.call
end
end
2. sidekiq.ymlにsucheduleの設定を行う
:scheduler:
:schedule:
send_line_message_job:
every: '2m' #一旦2分に一回送る
class: "SendLineMessageJob"
queue: default
3, 実装の確認をする
sucheduleの設定を完了したら、一度サーバーを再起動してください
その後、Sidekiqのターミナルで下記画像の用になっていたら、設定完了です
### この部分で設定が確認できます
Scheduling send_line_message_job {"every"=>"2m", "class"=>"SendLineMessageJob", "queue"=>"default"}
2分ごとにメッセージが送られていたら成功です
感想
今回では、ローカル環境のみでの実装を記述しました
次の記事で、Render.com(本番環境)でのデプロイまでの実装を記述しています
Redis,Sidekiqなど聞きなれない言葉での実装で最初は全然理解が進まなかったですが、少しずつ調べていき、結果として視野が広がったと感じたのでこの実装に挑戦して良かったなと思いました
Discussion