Slackの公式リマインダーが(日本の)祝日を解釈してくれないので、祝日を除外したSlackリマインダーを作りました。
tksugimoto/aws-lambda_slack-reminder-except-holiday
特徴
- 土日祝日はリマインドしない
- 年末年始など任意休日も設定可能
- リマインダーをテキスト形式で管理可能(Slack Reminder as Code)
- リマインダーの作成 / 変更の反映はコマンド一発
terraform apply
module "slack_reminder_sample" {
source = "./slack_reminder"
prefix = "${var.prefix}"
iam_for_lambda_arn = "${aws_iam_role.iam_for_lambda.arn}"
# ↓ ここから設定 ↓
name = "lunch"
reminder_text = "そろそろお昼です"
schedule_name = "every_day_11-30am_JST"
schedule_expression = "cron(30 2 * * ? *)"
slack_webhook_url = "${var.slack_webhook_url}"
# 祝日追加(年末年始など)
additional_holidays = "12/30-31 1/1-7"
}
経緯
- Slackのリマインダー機能で平日の夕方にリマインド投稿を設定していた
- 2016年の勤労感謝の日(11/23)は水曜日だったのでSlackで設定した平日のみのリマインダーはいつもどおり実行された
- BOSS
仕組み
毎日のリマインダー
- AWS CloudWatch Eventsのスケジューラーを使って毎日定刻にAWS Lambda起動
- AWS LambdaからSlackのIncoming WebHooksを使ってSlackに投稿
- AWS Lambda関数内で土日・祝日・独自定義休日の判定を行ない平日のみ投稿
上記環境の自動構築
-
Terraformを使用
- Terraformを使うことでリマインダーをテキスト形式で管理可能
- AWS Lambdaの環境変数とTerraformのmodule機能でリマインダーの複数定義をサポート
設定例・書式
module "slack_reminder-2" {
source = "./slack_reminder"
prefix = "${var.prefix}"
iam_for_lambda_arn = "${aws_iam_role.iam_for_lambda.arn}"
# ↓ ここから設定 ↓
name = "lunch" # AWSのマネジメントコンソールに表示されるのでわかりやすく一意なもの
reminder_text = "そろそろお昼です"
schedule_name = "every_day_11-30am_JST" # AWSのマネジメントコンソールに表示されるのでわかりやすいもの
schedule_expression = "cron(30 2 * * ? *)" # ※ UTCなので日本時間-9時間
slack_webhook_url = "${var.slack_webhook_url}"
# 祝日追加(年末年始など)
additional_holidays = "12/30-31 1/1-7"
# オプション設定(設定なし/空文字の場合はWebhookのデフォルト値)
channel = "#random"
username = "reminder bot"
icon_emoji = ":bento:"
}
※ 適切なシンタックスハイライトが無かったので、一番見やすいと思ったbashにしてあります
↑のリマインダーは↓のようになります。
2016年の天皇誕生日12/23(金)にはリマインドされてないことが確認できます。
設定のサンプル 30_main.tf.sample を見てもらえればどんな書き方があるのか分かりやすいと思います。
注意点は、スケジューラーはUTCなので、 schedule_expression
に書く時刻は日本時間-9時間である必要があることです。
スケジュール書式の詳細は → Rate または Cron を使用したスケジュール式 - AWS Lambda
使い方
tksugimoto/aws-lambda_slack-reminder-except-holidayのREADME参照。
料金
通常のリマインダーなら無料枠内で収まります。
実行環境 AWS Lambda
無料枠が多いのでこのリマインダーによって課金されることは通常は無いと思われます。
100 万件 1 か月あたりの無料リクエスト数
1 か月あたり最大 320 万秒 1 か月あたりのコンピューティング時間
12 か月間の AWS 無料利用枠期間終了後にも期限切れになりません。
実際の実行時間のログ(一例)を以下に示します。
Duration: 6.08 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 17 MB
Duration: 2.08 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 12 MB
Duration: 49.61 ms Billed Duration: 100 ms Memory Size: 128 MB Max Memory Used: 16 MB
Duration: 749.63 ms Billed Duration: 800 ms Memory Size: 128 MB Max Memory Used: 18 MB
Duration: 983.10 ms Billed Duration: 1000 ms Memory Size: 128 MB Max Memory Used: 20 MB
Duration: 719.58 ms Billed Duration: 800 ms Memory Size: 128 MB Max Memory Used: 20 MB
Slack(Incoming Webhooks)へ通信しない休日は100 ms
以下で、通信する平日は800m s
程度でした。
簡単のために毎日が平日で1000 ms / day / reminder
のLambda実行がされたとすると、無料枠を超えるには約10万リマインダーの設定が必要です。これは1秒に1回以上リマインドされる計算になります。
なお、無料枠を既に超えている場合は、メモリの最小単位128MBで $ 0.000000208 / 100 ms
なので、1種類のリマインダーを1ヶ月動かすと、
$\, 0.000000208 / 100\, \mathrm{ms} \times 1\, \mathrm{s} / \mathrm{reminder} \times 31\, \mathrm{reminder} / \mathrm{month} = $\, 0.00006448 / \mathrm{month}
日本円で約 0.007円となります。
定期的な実行 AWS CloudWatch Events
とても安いので無視してよいと思います。
100万リクエストで $1
だそうなので、約300種類のリマインダーを1ヶ月動かすと1円になります。
Amazon CloudWatch Events - Custom Events
$1.00 per million custom events generated
祝日判定
Node.jsのpackage japanese-holidays を使っています。
npmでインストールできて、依存が少ないものを選択しました。
その年の祝日をすべて計算しているので若干計算量が多いですが、AWS Lambdaが十分高速&1リマインダーで1回しか呼ばないので計算時間は誤差と判断しました。
- Qiita: 日本の休日を求める(休日判定) - Qiita
- npmjs: japanese-holidays
- ソースコード(GitHub): osamutake/japanese-holidays-js: Provides utilities to manipulate japanese holidays.