🐈

【Rails】Sidekiq + RedisでLINEで予定の前日にリマインド通知を送信する機能を作ってみた

2024/06/16に公開

はじめに

業務でLINEのリマインド機能を作成したため、備忘録として作成します。
注)環境構築などは今回の記事では省略させて頂きます。

出来ること

明日の予定が存在する場合にLINEでメッセージを送信出来ます。

使用環境

ruby 3.2.1
rails 7.0.8
MacBook(M3)

参照

https://railsguides.jp/active_job_basics.html
https://developers.line.biz/ja/reference/messaging-api/

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'

参照

https://github.com/sidekiq/sidekiq
https://github.com/sidekiq-scheduler/sidekiq-scheduler
https://github.com/line/line-bot-sdk-ruby

インストール

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のみを引数として渡すようにします。

参照

https://zenn.dev/stomk/articles/11f8c0dba0303e

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でメッセージのデザインを調整できます。

参照

https://developers.line.biz/ja/docs/messaging-api/using-flex-messages/

Flex Messageは、通常のLINEメッセージに比べ、より豊かでインタラクティブなレイアウトが可能なメッセージです。通常のLINEメッセージでは、テキスト、画像、動画など1種類のソースしか配信されません。しかし、Flex Messageでは、CSS Flexible Box(CSS Flexbox) (opens new window)の仕様に基づいて、レイアウトを自由にカスタマイズできます。

7.JOBの起動

bundle exec sidekiq

メッセージが送信されることを確認出来ました。

まとめ

今回はsidekiqを使って機能の実装をしましたが、他にもバックグラウンドジョブとして、good_jobschkedなど、色々とありそうなので試してみたいですね。

参照

https://techracho.bpsinc.jp/hachi8833/2024_06_07/126782#job

Discussion