GAS × Slack App で当番をローテーションする通知botを作る

こんにちは。株式会社 Interfamilia の Waka です。
2025年初の記事投稿になります。

今回の記事では、弊社の業務効率化のために組んだSlack bot について紹介したいと思います!


目次

背景

弊社では、毎週欠かさず社内の掃除を行っています🧹
オフィスを綺麗にすることで、気持ちよく仕事に臨めています✨

ですが、問題もありました。

掃除当番を毎週ローテーションで回しているのですが…
参加メンバーが増えるにつれ、今週の当番が誰なのか、パッと分からなくなってきたのです😭

標準Slack botではローテーション通知ができない
標準Slack botではローテーション通知ができない

毎週、Slackbotで↑のような通知を出していたのですが、これでは誰が当番なのか分かりません。

過去スレを辿り、先週は誰が当番だったか思い出し、ローテーションして今週の当番を記録。
翌週、翌々週も同じことの繰り返し…そんな運用を続けていました。

“自動でローテ回して「今週の掃除当番はこの人です!」とメンションしてくれる。
そんな便利なbotがあったらいいのになぁ…”

そんな風に考えてました。
調べてみたところ…理想的なSlackbot実装案が見えてきたので、作ってみました。


実装手順

当番通知Slack botの実装手順は、以下の通りです

  1. Slack App作成 → GAS連携
  2. GASスクリプト実装
  3. GASを定期実行するトリガー追加
  4. 運用開始

[手順1] Slack App作成 → GAS連携

bot用のSlack Appを作成。GAS (Google Apps Script) と連携させます。
この設定手順については既に多くの記事で紹介されていて、説明する事が無いので割愛します。

自分は以下の記事を参考にしました。

【参考リンク】


[手順2] GASスクリプト実装

GASスクリプトコードを javascriptで記述していきます。
以下のようなコードを書きました。

// main
function myFunction() {
  //  PropertiesService
  const scriptProperties = PropertiesService.getScriptProperties();

  const token = scriptProperties.getProperty('SLACK_TOKEN');
  const slackApp = SlackApp.create(token); // トークンを渡してSlack App作成
  const channelId = '#channel';

  // Slackメンション用メンバーリスト
  const user1 = scriptProperties.getProperty('USER1');
  const user2 = scriptProperties.getProperty('USER2');
  const user3 = scriptProperties.getProperty('USER3');
  const members = [user1, user2, user3];

  // COUNT定数呼び出し
  let count = parseInt(scriptProperties.getProperty('COUNT'));

  // 担当ローテーション実行
  const todaysMember = rotateArray(members, count % members.length)

  // メッセージ組み立て
  const message = [
  '【タスク当番のお知らせ】',
  '',
  '今週の当番はこちらです:point_down:',
  '',
  '・タスク1: ' + todaysMember[0],
  '・タスク2: ' + todaysMember[1],
  '・タスク3: ' + todaysMember[2],
].join('\n');

  // Slackメッセージ送信
  slackApp.postMessage(channelId, message);

  // COUNT定数のインクリメント・保存
  count += 1;
  if (count === 30) {
    // 30くらいを目途に定数を初期化
    count = 0;
  }
  scriptProperties.setProperty('COUNT', String(count));
}

// ローテーション関数
const rotateArray = function(collection, k) {

  for (let i = 0; i < k; i++) {
      collection.unshift(collection.pop());
  }

  return collection;
}

以下、コード実装にあたってのポイント紹介です。


a. Slack App連携・メッセージ送信

GASでSlackメッセージを送信する時、以下の手順を踏みます。

i. Slack App呼び出し
const slackApp = SlackApp.create(token);

Slack Appを用意します。ここで予め用意したSlackトークンを使用します。
xoxb- から始まる「Bot User OAuth Token」です。

ii. メッセージ本文の組み立て
  // メッセージ組み立て
  const message = [
  '【タスク当番のお知らせ】',
  '',
  '今週の当番はこちらです:point_down:',
  '',
  '・タスク1: ' + todaysMember[0],
  '・タスク2: ' + todaysMember[1],
  '・タスク3: ' + todaysMember[2],
].join('\n');

メッセージ本文。普通の文字列でOKです。
自分は可読性重視で、string配列 × join('\n') で改行を挟むようにしてます。

⚠️ Slackユーザーにメンションを飛ばしたい場合は、注意が必要です。

ただ単に @ユーザー名 と書くだけでは、普通の文字列とみなされてしまいます。
ユーザーの「メンバーID」を取得して <@XXXXXXXXXXX> という形式で指定しましょう。

以下の記事が詳しいです。

【参考リンク】 GASからSlackメンションする時のまとめ #効率化 - Qiita

iii. メッセージ送信
slackApp.postMessage(channelId, message);

最後に postMessage() でメッセージ送信。
チャンネルID、メッセージ本文を引数で指定します。


b. ローテーション関数

// ローテーション関数
const rotateArray = function(collection, k) {

  for (let i = 0; i < k; i++) {
      collection.unshift(collection.pop());
  }

  return collection;
}

当番を毎週ローテーションする関数。
今回のbot実装で一番悩んだポイントです。

試行錯誤の結果、以下の Array関数の組み合わせで作りました。

メンバー全員が入った配列を用意。[COUNT定数] % [メンバー人数] の値分、pop() → unshift() を繰り返す。
処理完了後、COUNT定数 を+1 インクリメントして、次回に持ち越す。
これにより、最小限の労力でローテーションを回しています。

COUNT定数 は、放置すると無限に数値がインクリメントされてしまうので、
30くらいを目途に一旦0にリセットする実装も組んでます。


c. PropertiesServiceによる定数の保持

GASには「PropertiesService」という機能があります。
スクリプトの外部に、Key-Value形式で定数データを永続的に保存できます。

プロパティ サービスを使用すると、1 つのスクリプト、1 つのスクリプトのユーザー、またはアドオンが使用されている 1 つのドキュメントにスコープされた Key-Value ペア形式のシンプルなデータを保存できます。通常、デベロッパーの設定やユーザー設定を保存するために使用されます。プロパティはスクリプト間で共有されません。

プロパティ サービス  |  Apps Script  |  Google for Developers

今回、以下のようなデータ保存にPropertiesServiceを使っています。

  • GASスクリプトに直接埋め込みたくない定数データ
    • Slackトークン、ユーザー名 etc…
  • 値を保存しておき、次の実行時に使い回したい定数データ
    • ローテーション関数で使う COUNT定数 をインクリメントした後、保存しています
PropertiesService の使い方

Google Apps Scriptメインページ > プロジェクトの設定 > スクリプト プロパティ に移動。
スクリプト プロパティを追加」から、データ登録が可能です。

プロジェクトの設定 > スクリプトプロパティ
プロジェクトの設定 > スクリプトプロパティ

「プロパティ」がKey、「値」がValueです。いずれもstring型で保存されます。
※ 上記画像の COUNT: 16 も number型ではなく string型です。

// PropertiesServiceからデータ取得
const scriptProperties = PropertiesService.getScriptProperties();
const token = scriptProperties.getProperty('SLACK_TOKEN');

// PropertiesServiceのデータ更新
const number = 1;
scriptProperties.setProperty('COUNT', String(number)); // string変換して保存

保存したデータを操作する時は、↑のように Propertiesオブジェクトの各メソッドを使います。
以下の公式ドキュメントが詳しいです。

【参考リンク】 Class Properties  |  Apps Script  |  Google for Developers


[手順3] GASを定期実行するトリガー追加

GASスクリプトができたら、それを定期実行するためのトリガーを追加します。

Google Apps Scriptメインページ > トリガー と移動。「トリガーを追加」で登録できます。

時間ベースのトリガー (週ベース) を作成
時間ベースのトリガー (週ベース) を作成

[例] 毎週木曜9:00-10:00頃に通知するbotを作りたい場合、以下のように設定します。

  • 実行する関数:GASスクリプトのmain functionを指定
  • イベントのソース:時間手動型
  • 時間ベースのトリガーのタイプ:週ベースのタイマー
  • 曜日:毎週木曜日
  • 時刻:午前9時~10時

[手順4] 運用開始

設定が終わったら運用開始です。
トリガーが上手く動けば、指定時間帯にSlackメッセージが送信されます💪

運用開始!🏃
運用開始!🏃

自分のSlack bot通知はうまく機能しました🎉
社内でも評判が良かったです(嬉しい)


今後の課題

今回実装したSlack botが抱える課題です。

[課題1] 例外的ケースには非対応

以下のような例外的ケースには、現状非対応です😭
スクリプトを一部書き換えたり、定期実行を一旦停めるなど、手作業での変更が必須となっています。

  • メンバー増減があった場合
  • 長期休暇などで一定期間botを止めたい場合

これらの自動化も技術的には可能なハズ。必要性が増したら対応を検討したいです。

[課題2] 実行される時刻があいまい

GAS標準の時間主導型トリガーは、スクリプトの実行時刻を正確に指定できません。
「毎週火曜日 12時~13時」といった具合に、かなりブレがあります。

自分が作ったbotは時刻「9時~10時」で設定しましたが、
9:40に動いてたり、9:50に動いたりと、非常に不安定です。

なお、正確な時間指定は、Googleカレンダー連携で実現できそうです。
(イベントの何分前に通知する、といった設定で可能)
現状あまり困ってないので優先度は低いですが、いずれ対応したいです。


最後に

以上、GAS × Slack API連携でタスク当番通知botを組んだ話でした。

「今週は誰が当番だったっけ…?」
「先週こうだったから、今週の当番は〇〇さんだ!あれ?違ったっけ?」
といった会話が不要になり、業務最適化が図れたのではないかと思います☺️

課題も見つかったので、それらを解消してより良いSlack botを組み、更なる効率化を目指したいですね。

それではまた次回!


参考リンク


会社を一緒に盛り上げてくれる仲間を募集しています!

応募フォームには、外部サービスengageを利用しています。
ご応募に際して、何かわからないことなどございましたら こちら からお気軽にお問い合わせください。