😇

Google Apps Scriptとスプレッドシートで非同期処理(Queue)

2025/03/23に公開

はじめに

今回、とある社内のフローを効率化するため、Slackとスプレッドシートを連携するツールをGAS(Google Apps Script)で開発することになりました。
しかし、開発を進める中で、いくつかの大きな壁にぶつかりました。

直面した問題

1. スプレッドシートのアクセス権限

社内情報ということもあり、スプレッドシートのアクセス権限は「組織内のみ」に制限されていました。
GASで作成するAPIも同様に制限され、外部からのSlack Webhookリクエストを直接処理できませんでした。

2. Slack APIのレスポンスは3秒以内

Slack APIでは、3秒以内にレスポンスを返す必要があります。
しかし、GASからスプレッドシートの参照・更新処理を行うには時間がかかり、この制約が大きな課題となりました。

試した方法

1. Cloud FunctionsからGASをコール

GCPのサービスアカウントが必要で、権限付与も煩雑でした。
そもそも、GASの関数をコールするのに3秒以上かかってしまうようでした。

2. 他のGASからGASをコール

権限付与の問題は解決できませんでした。
同様に、GASの呼び出しに時間がかかりました。

3. GASのトリガー機能で遅延実行

そもそも、GASの処理内でトリガー設定するのに3秒以上かかり、断念しました。

Queueで非同期実行しよう!

これらの問題を解決するために、Queue(キュー)を用いた非同期処理の仕組みをGAS上に実装しました。具体的には、以下の2つのGASプロジェクトとスプレッドシートを用意しました。

Queue(キュー)用GASプロジェクト + スプレッドシート

Slackなどからのリクエストを受け付け、処理待ちのデータをスプレッドシートに蓄積します。
このGASプロジェクトは、外部からのリクエストを受け付ける必要があるため、ウェブアプリケーションとして公開します。

Worker(処理実行)用GASプロジェクト + スプレッドシート

定期的にQueue用スプレッドシートを監視し、処理待ちのデータがあれば処理を実行します。
このGASプロジェクトは、外部からのリクエストを受け付ける必要はありません。

この構成により、Slackなどの外部からのリクエストはQueue用GASプロジェクトが即座に受け付け、処理はWorker用GASプロジェクトが非同期で実行するため、3秒のレスポンス時間制限をクリアすることができます。また、スプレッドシートのアクセス権限も、Queue用とWorker用で分離することで、セキュリティを確保することができます。

ソースコード

検証用の実装はClaspというパッケージを利用して開発しました。
ソースコードは以下のリポジトリを参照ください。

https://github.com/takemo101/gas-queue-example

Queueクラス

キューの追加(enqueue)と取得(dequeue)を行うシンプルなクラスです。

https://github.com/takemo101/gas-queue-example/blob/b8cd9bc2209f5c6908e416576dfd33c6b92d0343/packages/lib/src/queue.ts#L1-L138

排他ロッククラス

Worker側で重複実行を防ぐための排他ロックをGASのキャッシュ機能で実装しました。

https://github.com/takemo101/gas-queue-example/blob/899f1d2f5233c6bddff6df4c54b729e010644a09/packages/lib/src/lock.ts#L1-L104

Queueメイン処理(doPost)

外部からのリクエストを受け取り、キューに追加します。

https://github.com/takemo101/gas-queue-example/blob/899f1d2f5233c6bddff6df4c54b729e010644a09/packages/queue/src/main.ts#L1-L16

Workerメイン処理(handleQueue, addTrigger)

キューからデータを取り出し、処理を実行します。
定期トリガーでhandleQueueを1分ごとに実行します。

https://github.com/takemo101/gas-queue-example/blob/b8cd9bc2209f5c6908e416576dfd33c6b92d0343/packages/worker/src/main.ts#L1-L58

GASの追加手順

1. Queueのソースをデプロイする

Queue用のスプレッドシートを作成し、GASを作成。
Claspからソースコードをデプロイします。

2. Queueをウェブアプリとして公開する

Slack APIなどからアクセスできるよう、ウェブアプリとして公開し、URLを控えます。


3. Workerのソースをデプロイする

WorkerのGAS単体としてClaspでソースコードをデプロイします。

4. addTriggerを実行する

Workerのデプロイ後、addTrigger関数を実行してトリガーを追加します。

Queueを実行してみる!

今回の検証では、以下の手順でQueueシステムの動作確認を行いました。

1. APIクライアントツールでデータ送信

PostmanなどのAPIクライアントツールを使用し、Queue用GASプロジェクトのウェブアプリケーションURLへPOSTリクエストを送信しました。

2. Queueスプレッドシートの確認

データ送信後、Queue用スプレッドシートを開き、送信したデータが新しい行として追加されていることを確認しました。

3秒以内に処理されていることも確認しました。

3. Workerログの確認

Worker用GASプロジェクトの実行ログを確認しました。
ログには、WorkerがQueueスプレッドシートを定期的に監視し、新しいデータを発見して処理を実行した記録が残っていました。

まとめ

今回の開発では、GASを用いてSlackとスプレッドシートを連携させるツールを構築し、Queueによる非同期処理を実装しました。これにより、Slack APIのレスポンス時間制限をクリアし、スプレッドシートのアクセス権限の問題も解決できました。

Worker側の処理が1分ごとのトリガー実行であるため、即時性は求められませんが、社内ツールとしては十分機能します。GASだけでも工夫次第で様々なツールが開発できることを実感しました。

ただし、今回の構成では以下の点に注意が必要です。

  • 排他制御の実装
  • エラーハンドリング
  • トリガーの管理
  • スケーラビリティ

これらの点を考慮することで、より安定したシステムを構築できます。
GAS開発を行う上で、今回の経験が参考になれば幸いです。

株式会社ソニックムーブ

Discussion