Script(以下GAS)で実装していますが、3秒ルールの壁があってイベント処理がタイムアウトしてしまうという課題がありました。Slackの公式ドキュメントには3秒以内にレスポンスできない処理は、一旦レスポンスして非同期処理でイベントのペイロードにあるレスポンスURLに書き込めとありました。GAS内で非同期処理を行うには、トリガー処理を組み合わせして実現できそうでした。使えそうだと判断しました。GASのTriggerについてspikeしてみたまず軽くドキュメントをみて気になったのは1スクリプトにつき1ユーザーが20トリガーまでという制約が目につきました。https://developers.google.com/apps-script/guides/services/quotas#current_limitations実際にトリガーを使って非同期処理をさせてみましたが、イベント発火したトリガーは残り続けてしまい、すぐに制約に引っかかってしましました。非同期処理実行時のパラメータの受け渡しも、GASの機能としてはありませんでした。スプレッドシートにデータを書き込んでそれをイベントとして非同期処理させる例も見かけましたが、単純に非同期処理する為だけにスプレッドシートを用意するというのも大げさだし、外部要因が増えることになるのでコントローラブルではないなと見送りました。やったか?非同期処理のパラメータも含めてジョブとしてステータス管理をさせるようにしたジョブのデータのストレージとしてスクリプトキャッシュを利用しましたジョブの登録と実行処理を関数化して、キュー実行できるようにしたジョブの登録時にトリガーを作成し、トリガー実行された関数からキューをフェッチして処理を行うようなインターフェースを定義しました。アプリケーション側からはトリガーを意識せずにジョブキューの様に振る舞うようにしました。内部的にはスクリプトロックを使った排他制御だったり、ジョブのconsume時にジョブのステータス管理をしてコールバック関数が完了したら次回以降にゴミとなったトリガーを回収するようにさせました。いくつかのbotで作成した関数を組み込んで、動作検証&リファクタリングを行っていきました。とあるbotではジョブを時間指定させたいニーズがあったので、作成した関数を拡張して遅延実行もできるようにしました。ライブラリ化へリファクタリングを経て安定化もしてきていい感じになってきたのですが、作成していたbotが片手では足りなくなってきたタイミングぐらいから関数の管理が辛くなってきました。botの作成時期がバラバラで、途中でlinter入れたりjestを使い始めたりとで、作成した関数の微妙な差異も出てきてたりし始めていました。幾つか利用した実績はあったのですが、作成するのは初めてだったので色々苦労をしました。ライブラリ化で変更した点ランタイムをV8向けに作成していたのをwebpackでトランスパイルしてRhinoベースにダウングレードライブラリ自体がV8向けで作成していると利用するアプリもV8にしないといけないみたいだったので手を入れました。ライブラリ化するならサポートできる範囲が広い方が良いと考えました。単純に書き直すのも癪だったので、GASでnpmライブラリを動かす検証をする際にwebpackを使っていたので、使いまわしてみました。元々はクラスのみで機能提供していましたが、ライブラリ化に伴いグローバル関数として定義しないといけなかったので必要な機能のみを関数として切り出しました。JSDoc追加I/F定義をJSDocでまとめました。実際のライブラリのコード上はトランスパイルされているので型情報は失われていますが、記載しておくとGASのエディタ上のコード補完時に戻り値の型等が表示されるようになります。最近はclaspを使ってTypescriptで記述することが殆どだと思うので、型定義ファイルも用意しました。使い方セットアップライブラリをスクリプトに追加するには、GASのコードエディターで次のように操作します。"ボタンをクリックします。ドロップダウンボックスでバージョンを選択します(最新バージョンを選択してください)。"ボタンをクリックします。非同期処理用の関数オブジェクトを、パラメータも含めて登録します。内部的には、即時実行のトリガーが生成されます。"asyncFunction");};ジョブ登録時に指定された関数はトリガーを介して実行されます。ジョブを消費するコールバック関数と、トリガーされた関数の名前を指定します。指定したコールバック関数は、非同期処理の本体となります。コールバック関数は、ジョブ登録時に指定したパラメータを受け取ることができます。内部的には、コールバック処理が完了するとトリガーは削除されます。遅延実行についても呼び出す関数名が違うだけでほぼ同じ感じで使えると思います。やってみてすべてV8ベースで統一できたほうが楽どれだけニーズがあるかわからないし、いずれサポート外になると思われる環境向けにwebpackの環境まで用意するのはヘビーでした。あと後述する型定義も考えるとどういう形が望ましいか?まだ自分の中でうまく咀嚼できない状態です。グローバル関数故のモジュール化で悩むクラスライブラリを提供するという感じではないので、どう必要な機能を切り出すのかについて悩みました。アプリケーションの呼び出し側で書き味が変わらないように型定義ファイルを用意したりしましたが、今回の記述方法で正解だったのか?まだ手探りな感じです。testではライブラリ部分をすべてモックにしないといけない良い側面でもありますが、テストもいい感じに書けるようにするには前述のモジュールの切り方だったりが重要になります。jest周りの整備も含めてまだまだノウハウ貯めないといけないのが課題だと感じています。これは所感とかではないのですが。ダッシュボードから確認ができるというのがありました。Loggingが表示されないという仕様がありました。それがこちらのテクニックを使うことでWebアプリケーションでもデバックが楽になりました。やってないことリトライ処理の実装ジョブのタイムアウト処理の実装ジョブステータスの管理上は、上記のリトライやタイムアウトは意識していましたが、如何せん簡易的な実装になっているので対応はしていません。一般的なjob-queueのシステムと違ってワーカーがいるわけではなく、triggerでイベントが発生した場合にジョブを捌いているだけなので定期的にステータスを監視することができないのでやっていません。botを作成するというニッチなニーズを満たす為に作成したライブラリですが、GAS自体で実行時間が6分を超える場合に処理が強制終了する制約があるのでまあまあ使えるのではないでしょうか。ライブラリの公開I/Fの定義の部分など、まだ手探りな部分もありますので、是非ご意見等を頂けるとありがたいです。Golangバッジを贈って著者を応援しようバッジを受け取った著者にはZennから現金やAmazonギフトカードが還元されます。2024/03/11紹介したGASライブラリがバージョンアップしています。Proよくある質問LinksX(Twitter)GitHubメディアキットLegal利用規約プライバシーポリシ。