
目次
現場アプリをAppSheetで作り、ボタンを押したら自動で記録が残る——ノーコードで業務が回り始めると、社内の反応は一気に変わります。ところが運用を始めてしばらく経つと、こんな声が上がることがあります。
「同じ内容が2件、登録されているんですけど」
実案件(匿名)で私たちが経験したのも、まさにこれでした。ユーザーの操作は1回。それなのに、AppSheetのBot(自動化)が2回走り、データが2セット作られていたのです。
この記事では、なぜノーコードの自動化で二重登録が起きるのか、そして「アプリ側だけでは防げない」理由と対策を整理します。
起きたこと:1回の操作で、処理が2回走る
症状はシンプルです。ユーザーがアプリ上でボタンを1回押すと、Botが起動して外部処理(GAS)を呼び出す。その結果として作られるはずのデータが、なぜか2セット存在する。
厄介なのは、毎回必ず再現するわけではない点です。「たまに二重になる」という状態は、原因の切り分けが難しく、現場では「操作ミスでは」と片付けられがちです。しかし調べてみると、アプリの作り方そのものに原因がありました。
原因:Grouped Actionの各サブアクションが、それぞれイベントになる
AppSheetには、複数のアクションをまとめて順番に実行するGrouped Actionという仕組みがあります。「ステータスを更新して、日時を記録して、フラグを立てる」といった一連の操作を、ボタン1つにまとめられる便利な機能です。
問題は、ここです。Grouped Actionの中の各サブアクションが、それぞれ別々のデータ変更イベントとして扱われることがあります。つまり、ユーザーから見れば「1回の操作」でも、Botから見れば「複数回のデータ変更」なのです。
Botはデータが変わるたびにトリガー条件を再評価します。その結果、条件を満たすタイミングが複数回訪れ、同じレコードに対してBotが多重発火する。これが二重登録の正体でした。
なお、AppSheetの仕様は変わるため、Botのトリガー挙動やGrouped Actionの扱いについては、最新の情報を必ず公式ドキュメントで確認してください。
対策1:Bot側は「値がすべて揃った状態」だけで発火させる
まず手を入れたのは、Botのトリガー条件です。
よくあるのは、「ステータスが◯◯になったら」といった単一の条件だけで発火させる書き方です。これだと、途中の中途半端な状態でも条件を満たしてしまい、複数回引っかかります。
そこで、条件を**「処理に必要な値がすべて揃った状態」として厳密に記述**しました。必要な項目が1つでも欠けていれば発火しない。すべて埋まった瞬間だけ、1回だけ発火する。こう書き換えることで、Grouped Actionの途中段階では条件を満たさなくなり、多重発火が大きく減ります。
考え方としては、「何かが変わったら動く」ではなく、**「完成した状態になったときだけ動く」**にする、ということです。
対策2:呼ばれる側(GAS)に冪等性を実装する
ただし、Bot側の条件を整えるだけでは不十分です。理由は単純で、二重発火の原因はアプリの作り方だけではないからです。
- ユーザーがボタンを二度押しする
- 通信が不安定で、端末側がリクエストを再送する
- 一時的なエラーで、リトライが走る
これらはアプリの設定では防げません。だから、呼び出される側——今回はGAS——に、**「同じ入力が2回来ても壊れない」性質(冪等性)**を持たせます。実装したのは次の3点です。
| 対策 | 目的 |
|---|---|
| LockServiceで排他制御 | 同時に走った処理を直列化し、同時書き込みを防ぐ |
| 処理済みステータスでガード | すでに処理済みなら、2回目は何もせず終了する |
| SpreadsheetApp.flush() | 書き込みを確定させ、次の判定が古い状態を見ないようにする |
とくに重要なのが2番目の処理済みガードです。処理を始める前に「このレコードはもう処理済みか」を確認し、済んでいれば黙って終わる。この1行の判断があるだけで、何回呼ばれてもデータは1セットしか作られません。
そして、ガードが正しく働くには、書き込みが確定していることが前提になります。1回目の処理が「済み」を書いたのに、それが反映される前に2回目が判定してしまえば、ガードはすり抜けます。だから排他制御と書き込み確定(flush)をセットで入れます。
全体像:入口と出口の二重防護
整理すると、対策は入口(AppSheet側)と出口(GAS側)の両方に置きます。
- 入口(AppSheet):そもそも余計に発火させない。値が揃った状態だけで1回発火する条件にする
- 出口(GAS):万一2回来ても、2回目は無害に終わる。ロック・処理済みガード・書き込み確定
どちらか一方では足りません。入口だけを直すと、ユーザーの二度押しや通信リトライで破綻します。出口だけを直すと、無駄な呼び出しが走り続け、動作は遅く、原因の切り分けも難しくなります。
教訓:ノーコードでも「壊れない設計」は必要
この一件で確認できたのは、シンプルな原則です。
ノーコードの自動化でも、冪等性の設計はプロコードと同じように必要になる。
ノーコードツールは「作りやすさ」で選ばれます。実際、AppSheetは短期間で現場アプリを立ち上げられる強力な選択肢です。ただし、作りやすいことと、壊れにくいことは別の話です。ボタンを押す人は必ず二度押しますし、電波の悪い現場では通信も必ず失敗します。
「正常に操作されれば正しく動く」ではなく、**「想定外の操作が来ても壊れない」**ところまで設計して、はじめて業務に乗せられます。とくに請求・在庫・受発注のように、データが1件増えるだけで実害が出る業務では、この違いが決定的です。
二重登録を疑うときのチェックポイント
- Botのトリガー条件が、途中の状態でも成立する書き方になっていないか
- Grouped Actionでまとめた操作が、複数のデータ変更イベントになっていないか
- 外部処理(GAS等)に、処理済みかどうかの判定があるか
- 同時実行を直列化する仕組み(ロック)が入っているか
- 「たまに二重になる」を操作ミスとして片付けていないか
まとめ
- AppSheetのBotは、Grouped Actionの各サブアクションごとにトリガー条件が再評価され、多重発火することがある
- 対策はBot側だけでは足りない。入口(条件の厳密化)と出口(GASの冪等性)の二重防護で守る
- GAS側はロックによる直列化・処理済みステータスのガード・書き込みの確定をセットで実装する
- 二度押しや通信リトライはアプリ設定では防げない。同じ入力が2回来ても壊れない設計が前提になる
- ノーコードでも、業務データを扱う以上、求められる堅牢さはプロコードと変わらない(各サービスの仕様は変わるため、最新は公式で確認)
RENOYでは、AppSheetやGASを使った業務自動化を、作って終わりにせず「現場の使い方で壊れないか」まで含めて設計しています。「すでに作ったアプリで、たまに変なデータが増える」といった段階のご相談も歓迎です。まずはお気軽に無料個別相談(オンライン・60分)をご利用ください。サービス内容をまとめた資料は資料請求からご覧いただけます。
