【Rails】Sidekiq + RedisでLINEで予定の前日にリマインド通知を送信する機能を作ってみた
はじめに
業務でLINEのリマインド機能を作成したため、備忘録として作成します。
注)環境構築などは今回の記事では省略させて頂きます。
出来ること
明日の予定が存在する場合にLINEでメッセージを送信出来ます。
使用環境
ruby 3.2.1
rails 7.0.8
MacBook(M3)
参照
1.LINE Developersに登録
LINEログイン機能を実装するには LINE Developersに登録する必要があります。
まだ登録されてない方はこちらのURL ( https://developers.line.biz/ja/ ) からログイン画面に遷移し, LINEの登録時に設定したメールアドレスとパスワードでログインします。
プロバイダーを選択し、新規プロバイダーを作成します。
Messaging APIのチャネルを作成します。
必要な情報を取得します。
チャネル基本設定のタブを選択して、チャネルシークレットを取得します。
Messaging API設定のタブを選択して、チャネルアクセストークンを取得します。
取得したチャネルシークレットとチャネルアクセストークンをenvファイルに設定します。
.env.development
LINE_CHANNEL_SECRET="取得したチャネルシークレット"
LINE_CHANNEL_TOKEN="取得したチャネルアクセストークン"
2.Gemfileに必要な機能を追記
Gemfile
# 非同期ジョブを処理するためのバックグラウンドジョブ処理ライブラリ
gem 'sidekiq'
# Sidekiqを使用して定期的なジョブ実行を行う
gem 'sidekiq-scheduler'
# LINE Messaging APIを簡単に利用出来る
gem 'line-bot-api'
参照
インストール
bundle install
3.Sidekiq の設定
config/sidekiq.yml
:concurrency: 5
:scheduler:
:schedule:
fetch_schedule:
cron: '0 8 * * *'
class: FetchScheduleJob
注)毎朝8時にJOB実行される仕様です。
cronの値を変更することでJOBの実行間隔を変更出来ます。
例)
5分ごとのJOB実行
*/5 * * * *
毎時0分にJOB実行
0 * * * *
4.予定(ミーティングを例に使用)をDBから取得する想定で設定
マイグレーションファイルを作成して予定を格納するテーブルを作成
rails g migration schedule
db/migrate/20240525150137_schedule.rb
class Schedule < ActiveRecord::Migration[7.0]
def change
create_table :schedules do |t|
t.string :title
t.datetime :start_at
end
end
end
app/models/schedule.rb
class Schedule < ActiveRecord::Base
end
5.予定を取得するJOBを作成
app/jobs/fetch_schedule_job.rb
class FetchScheduleJob < ApplicationJob
sidekiq_options retry: false
def perform
today = Date.current.in_time_zone
target_day = today + 1.day
schedules = Schedule.where(start_at: target_day.all_day)
if schedules.empty?
Rails.logger.info('予定が存在しません。')
return
end
schedules.each do |schedule|
LineRemindJob.perform_later(schedule.id)
rescue StandardError
Rails.logger.error('LINEへメッセージ送信中にエラーが発生しました')
next
end
end
end
注)JOBの引数ではIDのみを引数として渡すようにします。
参照
Sidekiq はジョブの引数を enqueue 時に JSON.dump して、dequeue 時に JSON.load している。このため、引数には string, integer, float, boolean, array, hash などの JSON で表現できる型のオブジェクトしか安全に渡すことができない。
Active Record のオブジェクトは渡すことができないため、代わりにレコードの ID を渡して、ジョブの中で find しなおす形になる。
6.LINEにメッセージを送信するJOBを作成
app/jobs/line_remind_job.rb
class LineRemindJob < ApplicationJob
include SendLineMessage
sidekiq_options retry: 3
def perform(meeting_id)
meeting = Meeting.find(meeting_id)
line_bot_client = line_bot_client()
# line_idはwebhookの情報などから取得出来ます
line_id = "送信先のLINE_IDを設定"
message_text = "明日の予定のお知らせです。\n\nタイトル: #{meeting.title}\n開始時刻: #{meeting.start_at.strftime('%H:%M')}"
send_line_message(line_bot_client, message_text, line_id)
end
private
def line_bot_client
Line::Bot::Client.new do |config|
config.channel_secret = ENV["LINE_CHANNEL_SECRET"]
config.channel_token = ENV["LINE_CHANNEL_TOKEN"]
end
end
def send_line_message(line_bot_client, message_text, line_id)
message = {
type: 'text',
text: message_text
}
response = line_bot_client.push_message(line_id, message)
if !response.code.to_i.between?(200, 299)
Rails.logger.error "LINEへのメッセージの送信に失敗しました: ステータス=#{response.code}, エラーメッセージ=#{response.body.inspect}"
end
end
end
Flex Messageでメッセージのデザインを調整できます。
参照
Flex Messageは、通常のLINEメッセージに比べ、より豊かでインタラクティブなレイアウトが可能なメッセージです。通常のLINEメッセージでは、テキスト、画像、動画など1種類のソースしか配信されません。しかし、Flex Messageでは、CSS Flexible Box(CSS Flexbox) (opens new window)の仕様に基づいて、レイアウトを自由にカスタマイズできます。
7.JOBの起動
bundle exec sidekiq
メッセージが送信されることを確認出来ました。
まとめ
今回はsidekiqを使って機能の実装をしましたが、他にもバックグラウンドジョブとして、good_jobやschkedなど、色々とありそうなので試してみたいですね。
参照
Discussion