はじめに
こんにちはスタディプラスでCTOしています島田です。
現在スタディプラスには新メンバーが続々と入社して、うれしい悲鳴があがっています。 その悲鳴にほんのり応えた例の紹介です。
課題
- Slackチャンネルが乱立(186のパブリックチャンネル)。そのため新メンバーが、どのチャンネルでどんな目的の会話をしているかを把握する事が困難
- 上記の理由により、質問や必要な情報を取得するチャンネルを探すコストが上がっていた
理想状態
- 新メンバーが必要なSlackチャンネルを、迷う事なくすぐに見つけられ発言ができることで業務を円滑に遂行することができる
アプローチ案
理想状態を実現する方法を幅広く考える。
- A) 全てのチャンネルを把握したメンバーを養成し、新メンバーが必要なチャンネルを聞く
- =>❌ : 属人性・コストが高い
- B) 定期的に不要なチャンネルを精査する
- => ⭕️
定期的に不要なチャンネルを精査する
- A) 毎月不要なチャンネルかどうかを聞いてまわってアーカイブする
- =>❌ : コストが高い
- B) 人力でSlackのアナリティクスから「最後にアクティブだった日」をCSVエクスポートして、そのCSVを利用してプログラマブルなアプローチをする
- =>❌ : 人力要素がある。CSVだとチャンネルIDがエクスポートされないで、扱いが複雑になりそう
- C) 不要なチャンネルを「最終投稿から一定期間投稿がない」と一旦定義して、Web APIを利用して過疎化しているチャンネルを探す。それを自動化して定期実行をする
- => ⭕️
Web APIを利用したアプローチ
このアプローチだけでは「理想状態」へ到達する事はもちろんできないです。しかしそのためのファーストステップとして、まず明らかに不要と思われるチャンネルのアーカイブを自動化するというアイデアは良いかと思いました。
今回やること
- 不要なチャンネル(30日間投稿がない)をアーカイブする
- ただしパブリックチャンネルでも
_
で始まる業務以外のチャンネルは除く。例)#_boardgame
- ただしパブリックチャンネルでも
- アーカイブ処理を自動化して定期実行をする
実現方法
で、実現方法を検討。 - A) チャンネルをアーカイブするプログラムを自分のPCでcrontabを実行する - =>❌ : 属人性が高い - B) チャンネルをアーカイブするプログラムを外部サービスを利用して定期実行 - => ⭕️
大きな課題解決に対する第一歩的でありお試しなので、限りなく運用負荷を低くしたいと思い、以下の技術を利用することにしました。
- Google Cloud Functions のHttpトリガーで、SlackのAPIをコールする。
- 上記をGoogle Apps Script のプロジェクトのトリガーを利用して定期実行をする
手順
- GCPの事前準備
- SalckのTokenを生成
- 実装
- Cloud Functions デプロイ
- Google Apps Scriptで定期実行を登録する
GCPの事前準備
HTTP のチュートリアル の「始める前に」を参考に事前準備。
SalckのTokenを生成
https://api.slack.com/apps より「Creaet New App」からAppをつくりトークンを生成 参考: Slack API 推奨Tokenについて
実装
プログラムの構成
- channels.list でチャンネル一覧を取得。
_
で始まるチャンネル以外を抽出- 最終投稿を知るために、channels.history で履歴を取得。( channels.info だとAppを作成したユーザーが参加しているチャンネルでないと
latest
が取得できなかったため ) - 各チャンネルの最終投稿が30日以上経過しているかチェック
- 対象となったチャンネルをchannels.archive でアーカイブを実行
- chat.postMessage で完了を通知
もろもろ準備
Node Slack SDK をインストール
$ npm init $ npm install @slack/client -s
アーカイブをする処理を実装
$ vim index.js
const { WebClient } = require('@slack/client'); const token = process.env.SLACK_TOKEN; const web = new WebClient(token); function archiveChannels(intervalDays) { web.channels.list({ exclude_archived: true }) .then((res) => { const publicChannels = res.channels.filter(c => c.name.indexOf('_') != 0 ); publicChannels.forEach(c => archiveForlornlyChannel(c, intervalDays)); // 通知するチャンネルのID postMessage('CXXXXXX', 'SlackArchiveを実行しました'); }) .catch(console.error); } function archiveForlornlyChannel(channel, intervalDays) { web.channels.history({ channel: channel.id }) .then((res) => { const ts = res.messages[0].ts; const latest = new Date(parseFloat(ts * 1000)); const now = new Date(); const diff = now.getTime() - latest.getTime(); const days = Math.floor(diff / (1000*60*60*24)); if (days > intervalDays ) { console.log(channel.id, channel.name, days); archiveChannel(channel); } }) .catch(console.error); } function archiveChannel(channel) { web.channels.archive({ channel: channel.id}) .then((res) => { console.log(res); }) .catch(console.error); } function postMessage(channel_id, text) { web.chat.postMessage({ channel: channel_id, text: text }) .then((res) => { console.log(res); }) .catch(console.error); } exports.ArchiveChannel = (req, res) => { archiveChannels(30); res.status(200).send('OK'); };
デプロイ
関数をデプロイ
$ gcloud beta functions deploy ArchiveChannel --trigger-http
Slackトークンの環境変数をデプロイ
$ gcloud beta functions deploy ArchiveChannel --set-env-vars SLACK_TOKEN=Slackのトークン
Google Apps Scriptで定期実行を登録する
Google Apps Script(以下GAS)にプロジェクトを作って、定期実行を登録する。
参考:無料でお手軽Cron!Google Apps Scriptを使ってみる
- GASにプロジェクトを作って、関数をコールするScriptを実装
- 定期実行をするトリガーを登録
function fetchToSlackArchive() { UrlFetchApp.fetch("https://ここに関数URL"); }
実行
- 設定した時間内で実行がされること(Slackに通知が来ること)を確認
- GCPのログビューアでみると55チャンネルがアーカイブされました
- Slakのアナリティクス
まとめ
Cloud Functions を利用して簡単に開発と実行を実現する事ができました。 本質的な課題解決までは遠いですが、まずはその橋頭堡となる仕組みが出来たのではないかと思います。
新しい概念・技術をいきなりプロダクション環境で導入するには腰が重くなってしまいがちですが、社内のプロセスを改善するためにサクッとお試し導入することで、その技術の良さや導入ハードルを経験する事ができたと思います。 スタディプラスでは社内システムやプロダクション環境で積極的に新しい取り組みや技術の活用をして行くことを検討しています。 こういった取り組みに共感ができる方、是非一緒に働きませんか! こちらよりお待ちしております。