【個人開発】GraphQL API を叩いて毎朝電気代が届くLine Botを開発する【後編】

## はじめに
今回の記事は **GraphQL API を叩いて毎朝電気代が届くLine Botを開発する**
の後編の記事となります。

今回は、`rake`を使用して、定期実行用のタスクを作成していくのと
`Render`の`Cron Job`を使用して定期実行を設定する方法について解説していきます！

前回の記事はこちらになります。

https://qiita.com/kim_t0814/items/d7346d19529ca2315fe3

## 実装方針
**1.Rails側からGraphQL叩いて電気代を取得出来るようにする
2.Line Messaging APIを利用して、取得した電気代情報をユーザーに送信する機能の実装　
-- 今回はここから下 --
3.開発環境で定期実行用のタスクを作成する
4.本番環境で定期実行を行えるようにする**

## 開発環境で定期実行用のタスクを作成する
今回定期実行用のタスクを作成するために、`rake`タスクを使用していきます。
rakeタスクは `lib/tasks`の配下に作成する必要があります。

```terminal
$ rails g task file_name
```
また、上記コマンドでも作成することが出来ます！

今回は下記コマンドを実行して作成してみましょう。

```terminal
$ rails g task line_notification
```


すると下記のようなファイルが作成されると思います。

```lib/tasks/line_notification.rake
namespace :line_notification do
end
```

さて、上記を以下のように変更します。

```lib/tasks/line_notification.rake
namespace :line_notification do
  desc "Send billing notification" # タスクの説明 description（説明）
  task send_billing_notification: :environment do # task名(`send_billing_notification`) 自由に命名可
    #　　実行したいロジック
    # 有効なRubyコードなら何でも書ける
    OctopusEnergyBillController.new.index
  end
end
```

ただ今回のコード、タスクを叩けば実際にLINEの通知が送られて
動作的に問題がありませんが良くない部分があります。

以下引用
>Action Controllerは、MVCアーキテクチャの「C」に相当します。リクエストを処理するコントローラがルーティング設定によって決定されると、コントローラはリクエストの意味を理解して適切な出力を行う役目を担います。

https://railsguides.jp/action_controller_overview.html

上記を見ての通り、今回の場合はリクエストを処理するわけではないので
適切ではありません(まあ動きはしますが)。

ですので今回は`app/controllers/octopus_energy_bill_controller.rb`の
実装を サービスクラスに移植します！

その前に軽く説明しておくと、サービスクラスとは
**ビジネスロジックを実装するためのパターンの1つ**です。
コントローラーやモデルからビジネスロジックを分離する、役割を果たします。

詳しくは、下記の記事に詳しく解説してあります`(自分も下記記事見て勉強した)`。

https://qiita.com/getty104/items/0915eb3b53ed7a265db2


コードは以下のようになります。

```app/services/octopus_energy_bill.rb
class OctopusEnergyBill

	GetBillQUERY = OctopusClient::Client.parse <<~'GRAPHQL'
		query(
			$accountNumber: String!
			$fromDatetime: DateTime
			$toDatetime: DateTime
		) {
			account(accountNumber: $accountNumber) {
				properties {
					electricitySupplyPoints {
						agreements {
							validFrom
						}
						halfHourlyReadings(
							fromDatetime: $fromDatetime
							toDatetime: $toDatetime
						) {
							startAt
							endAt
							value
							costEstimate
							consumptionStep
							consumptionRateBand
						}
					}
				}
			}
		}
  GRAPHQL

  def notify
    result = OctopusClient::Client.query(GetBillQUERY, variables: {
      accountNumber: ENV['OCTOPUS_ACCOUNT_NUMBER'],
      fromDatetime: Date.yesterday.beginning_of_day.iso8601,
      toDatetime: Date.yesterday.end_of_day.iso8601
      })

    properties = result.original_hash.dig("data", "account", "properties")
    electricity_supply_points = properties.first["electricitySupplyPoints"]
    half_hourly_readings = electricity_supply_points.first["halfHourlyReadings"]
    @kwh = half_hourly_readings.pluck("value").map(&:to_f).sum
    @cost = half_hourly_readings.pluck("costEstimate").map(&:to_f).sum
    text = "#{Date.yesterday.strftime('%Y年%m月%d日')}は#{@kwh.round(2)}kWh消費して#{@cost}円かかったよ"

		message = {
      type: 'text',
      text: text
    }
		LineBotClient.new.client.broadcast(message)
  end
end

```

`rake`タスクで実行するするインスタンスメソッドも下記のように変更します。

```diff_ruby:lib/tasks/line_notification.rake
namespace :line_notification do
  desc "Send billing notification" 
  task send_billing_notification: :environment do 
    #　　コントローラーだけはなく、サービスメソッドから呼び出すように変更
-   OctopusEnergyBillController.new.index
+   OctopusEnergyBill.new.notify
  end
end
```

さて、コマンドを実行してみましょう！

```terminal
$ rake line_notification:send_billing_notification # rake namespace:task_name 
```

すると...
予想通り、Lineに電気代の通知が届きます!

![LINE_capture_719973651.192517.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636995/1b429756-e564-f635-048e-7af34e283e10.jpeg)



## 4.本番環境で定期実行を行えるようにする
今回は、**Render** の **Cron Jobs**使用して定期実行を行なっていきます！

### そもそもRenderとは?

一言で言うと、WebアプリケーションをGithubと連携して簡単にデプロイできるPaasサービスです。

`heroku`が有料サービスのみの提供になりましたが、`render`に関しては
アプリケーションの実行時間は750時間・パイプラインの実行時間に関しては、500分まで無料です！

![スクリーンショット 2023-10-30 12.29.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636995/5e867345-6422-f867-6bdd-4921c5be2c3f.png)

データベースに関しても、90日間まで無料ですので検証用や個人のポートフォリオであれば問題ないかなと思います。

今回はそのRenderの中の定期実行させるための機能、 **Cron Jobs** を使用していきます！

因みに料金は以下に乗っています。

基本的に **1ヶ月1ドルが最低料金**となり、インスタンスタイプ毎に1分毎に**従量課金**が行われていきます。

https://render.com/pricing#cronjobs

また、主要な設定について説明いたします。

![screencapture-dashboard-render-cron-new-2023-10-26-20_22_04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636995/ffb38cc3-66ec-4804-fd2b-6f95fb3db2b2.png)

| 項目  | 説明 | 
| ------------- | ------------- |
| Name | Cronのユニークな名前|
| Branch | Cronjobが実行されるブランチ、今回テスト用で作業ブランチ・テスト完了後にmainで設定した。|
| Runtime | どの言語・環境で実行するか選択する。(例:Ruby,Docke,Go)|
| Build Command | 新しいバージョンのコードをデプロイ・ないしは設定を変更した際に実行するコマンド|
| Schedule | cron式に設定(例:30(分) 23(時) *(日) *(月) *(曜日 0-6 0が日曜) |
| Command | Scheduleに従って実行するコマンド(例:`rake line_notification:send_billing_notification `)|

また、時刻が23時30分と定義されているのは、UTC(協定世界時)とJST(日本標準時)で9時間時差があるので、
実際に実行されるのは日本時間の08:30になります。

次に、設定が終わったらEnvironmentから `.env` で設定した環境変数も
同様に定義しておいてください！

![スクリーンショット 2023-10-30 14.10.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636995/b82a4f4a-1de7-78fe-644e-d7c5e163eb65.png)

また、`SECRET_KEY_BASE`に関してはデプロイ時にエラーが発生したため環境変数と
`config/secrets.yml`に定義いたしました。

```config/secrets.yml
production:
  secret_key_base: <%= ENV["SECRET_KEY_BASE"] %>
```

少し補足しておくと、`secrets.yml`は暗号化通信通信のための設定ファイルで`secret_key_base`
を設定し通信を暗号化します。

さて、全ての設定が終了したら実際にcronが実行されるか確認します。

![LINE_capture_720336484.261465.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/636995/50738007-e398-a32c-bb36-d76c68146ac9.jpeg)

毎朝8時半に電気代の通知が来ることが確認できました！！

## 最後に
いかがでしたでしょうか。
以上で「GraphQL API を叩いて毎朝電気代が届くLine Botを開発」が完了です！！

また、オマケ版として`AWS Lambda`と`CloudWatch Events`を使用して、
定期実行する記事もいずれ執筆しようと思います。

ソースコードの方は下に置いておきます。

https://github.com/kimkim0814/octopus-energy-line-bot

最後まで読んでいただきありがとうございました!!

## 参考文献

https://railsguides.jp/command_line.html#%E3%82%AB%E3%82%B9%E3%82%BF%E3%83%A0rake%E3%82%BF%E3%82%B9%E3%82%AF

https://railsguides.jp/configuring.html

https://qiita.com/getty104/items/0915eb3b53ed7a265db2

https://dev.classmethod.jp/articles/github-render-deploy/

https://zenn.dev/takeyuwebinc/articles/065521abd7785d