複数回実行とは?
SlackBotに各人毎のGoogle MeetのURLを出してもらう で作ったSlackbotが
1回だけレスポンスを返す想定のはずがたまに2〜4回レスポンスを返してくることがありました
実害はなかったので無視していたんですが
最近新しく作ったbotでは深刻な問題だったので調査した結果解消することができました
原因
Slackからのリクエストに対してレスポンスを返すのに3秒以上かかるとリトライされる仕様を考慮できていなかったためでした
スプシ内での行の探索する処理が行数増えると遅くなるような実装になっていて
開発時やリリース当初は気付けず、しばらくしてから問題が起きていました
ちゃんと公式ドキュメントを見れば書いてあるし
ググればSlack Events APIの再送仕様と回避方法まとめ といった記事も出てくる
迷宮入りするような問題でもないのに2年以上放置するなんて怠惰ですね〜(自戒)
対処方法
処理の先頭でリクエストに含まれる client_msg_id
をキーにしてキャッシュに値を入れて
2回目以降のりトライされたリクエストの場合(キャッシュヒットした場合)は処理をせずレスポンスを返すようにしました
function doPost(e) {
const contents = JSON.parse(e.postData.contents);
// slackの3秒タイムアウトリトライ対策
let cache = CacheService.getScriptCache();
if (cache.get(contents.event.client_msg_id) == 'done') {
return ContentService.createTextOutput();
} else {
cache.put(contents.event.client_msg_id, 'done', 600);
}
// 時間かかる処理
.
.
.
return ContentService.createTextOutput();
なぜキャッシュなのか
- キューイングしてすぐにレスポンスを返すことをSlackは推奨しているが、GASでキューイングはめんどくさい
- リトライされたリクエストの場合ヘッダに
X-Slack-Retry-Num
がついてくるがGASではヘッダ検証できない
からです
以上!