実行セマンティクス、制約、セキュリティ
最終更新: 2026年7月21日
Script が ランタイムでどのように動作するか(順序、トランザクション、エラー、ロック)、保存時にどのような静的制約を受けるか、そして セキュリティモデルを整理します。文法は Statement カタログ と 値式、実践的な組み合わせは クックブック を参照してください。
実行順序とモード
statementsは 上から下へ順次実行されます。Returnに到達すると、その時点で終了します。- Sync はリクエストを処理する経路で、Async はバックグラウンドで実行されます。 実行場所の区別にすぎず、結果はどちらであっても
Returnの値です(呼び出しのレスポンス形式は Script 概要のリクエストとレスポンス、実行モード を参照)。 - 能力(capability)からモードへ: statement ツリーに
ExternalIo(Http外部呼び出し)、MediaIngest(Media ファイルのインジェスト。fields.fileの{ source, encoding }。url・base64 共通)、LongRunning(大量の Loop など)のいずれか一つでもあれば、executionModeはAsync強制になります。この三つは別個の能力であり、下記の 静的制約 でカウント対象が分かれます。
実行セマンティクス
Guard(事前条件)
専用の guard 文はありません。If と then:[Return] で表現します。条件に違反した場合は結果を返し、以降の statement は実行しません(guard のない Script も当然可能です)。
{ "type": "If", "condition": { "<": [ "{ /wallet/fields/balance/en-US }", "{ /payload/fields/cost }" ] },
"then": [ { "type": "Return", "value": { "ok": false, "reason": "insufficient credit" }, "statusCode": 402 } ] }トランザクションなしと best-effort 補償
Script は トランザクションではありません。 失敗した場合、エンジンはそれまでに行った操作の補償(compensation)を試み、エラーの原因を返しますが、次の制限があります(設計上許容しています)。
- 削除の取り消しは新しい
sys.idを作るため、これを指していた参照が壊れます(生成のロールバックは容易で、更新には before-image が必要です)。 - 外部効果(
Http)は不可逆です(すでに送信された呼び出しと課金は取り消せません)。 - プロセスがクラッシュした場合、未補償の状態(orphan)が残ることがあります。
真の原子性が必要な場合は、ユーザーが Script で直接補償するか、取り消せない操作(外部呼び出しなど)を最後に配置します。「連鎖はできるがロールバックはできず、しかも安全に見える」順序が最も危険です。
楽観的ロック
update/patch の競合は ResourceUpdate と ResourcePatch の version で絞ります。version(値式、Int)を渡すと、対象の現在の sys.version と 一致する場合のみ更新し、不一致の場合は バージョン競合エラーで abort されます(Try/catch で局所的に処理できます)。省略すると検査なしの last-write-wins になります。通常は ResourceRead や ResourcePageRead で先に読み込み、その sys.version を渡します(クックブックの楽観的ロック CAS を参照)。
origin 基準の書き込み
書き込みは常に origin(draft)に反映され、delivery(CDA/ACDA)への公開は publish で制御します(ResourceCreate/ResourceUpdate/ResourcePatch の publish、または ResourcePublish/ResourceUnpublish)。
何が失敗か
- 本当の失敗は statement のランタイムエラーです。
Httpの最終 status が 400 以上(4xx·5xx。ignoreStatusCode: trueなら失敗ではない)かタイムアウト、応答本文が 10MiB を超える、リソース操作の失敗(対象なし、バージョン競合、未対応の演算など)。このような失敗は エンジンが abort して補償し、Try/catch/finallyで局所的に処理できます。 Returnはエラーではなく正常な早期終了です。catchの対象ではありません(ユーザーによる throw の概念はありません)。catchの中では/errorで{ message, statement }を参照します。
サーバー側集計なし
count、sum、group-by 専用のサーバー操作はありません。ResourcePageRead の巡回と SetVar/JsonLogic で計算するため、fetch サイズと maxIterations に縛られます(数百万件の集計には不向きです)。
待機と遅延なし
Script には Delay 文はありません。Script はリクエスト経路(Sync)またはバックグラウンド(Async)で 一度実行されて終わりであり、外部 job が終わるまで内部で待機したりポーリングしたりしません(Async の結果は別です。呼び出し元が 202 で受け取った requestId でポーリングして Return の値を取得します)。
静的制約(保存時の検証)
以下は Script を 保存(作成/更新)する時点で検査されます。違反すると保存が拒否されます(ランタイムではなく作成時の失敗です)。
| 制約 | デフォルト値 |
|---|---|
外部 I/O があれば executionMode は Async | 該当なし |
Loop の body 内で Http 外部呼び出しと Media ファイルのインジェストを 禁止 | 該当なし |
定義ごとの Http 外部呼び出しの最大数 | 3(maxExternalIo) |
定義ごとの SetVar の最大数(ネスト含む) | 5(maxSetVar) |
| 定義ごとの 全 statement の最大数(ネスト含む) | 15(maxStatements) |
Http.retry の上限 | 2(maxHttpRetry) |
上限はサーバー設定(weegloo.core.script.*)で調整できます(上記はデフォルト値です)。
Media ファイルのインジェストは
MediaIngest能力であり、Http外部呼び出し(ExternalIo)とは異なり、maxExternalIo(3)の上限には含まれません。 ただしAsync強制とLoopbody 禁止はHttpと同じく適用されます。
時間予算(ランタイム)
| モード | デフォルト予算 |
|---|---|
| Sync | 10秒(syncTimeoutMs) |
| Async | 60秒(asyncTimeoutMs) |
プランごとの個数上限
Script は Billable リソースであり、Organization ごとの個数がプランごとに制限されます。
| Plan | Script の個数 |
|---|---|
| Free | 3 |
| Basic | 10 |
| Pro | 50 |
| Enterprise | 無制限 |
上限に達すると新しい Script の作成が拒否されます(他の Billable リソースと同じ経路です)。
セキュリティモデル
secret ヘッダー
Http.headers の secret:true の項目は CMA(管理者)専用であり、エンドユーザー(ServiceUser)には公開されず、送信の直前にのみ復号されます。LLM API キーのような秘密をここに置きます(App Bundle にパッキングされる際も secret 値はマスキングされ、元の space の外には出ません)。
実行アイデンティティと認可
- 実行アイデンティティ: 実行中のすべてのリソース操作は、
/executeを呼び出したユーザーのアイデンティティで実行されます。作成または更新されるリソースのcreatedBy/updatedByは呼び出し元となり、createdBy: ":self"スコープも呼び出し元を基準に解決されます。 - 認可の境界は二つであり、ランタイムでは statement ごとにリソース権限を再検査しません。
- 作成時(保存): Script を保存する際に、作成者がそれらの statement が使う リソースとアクションの権限を実際に持っているかを検査します。一つでも欠けていれば保存が拒否されます(
WGL403015)。つまり、権限のない操作を含む Script はそもそも保存されません。 - 呼び出し時(
/execute): 呼び出し元の Script Execute 権限のみを検査します。権限がなければ403です。通過すると、statement ごとのリソース権限はランタイムで再確認せずに実行します。プログラミングにおける関数の実行権限と同じ方式です。関数を実行する権限さえあれば、その中の個々の操作の権限は再び問われません。
- 作成時(保存): Script を保存する際に、作成者がそれらの statement が使う リソースとアクションの権限を実際に持っているかを検査します。一つでも欠けていれば保存が拒否されます(
- 所有権スコープ:
whereフィルターのcreatedBy: ":self"は「現在の呼び出し元が作成したものだけ」を意味します(例: 自分のウォレットのみ照会)。 - 委任された権限(作成時の注意): 上記の二つの境界を合わせると、Script の実行は 作成者の権限を委任されて行われるのと同じです。呼び出し元は Execute 一つだけあればよく、Script 内の statement は作成者が保存時に認可された範囲でそのまま実行されます。したがって、呼び出し元が自分自身ではできないリソース操作も Script を通じて起こりえます。作成者に付与された権限がそのまま その Script の影響範囲となるため、Script に含める動作は慎重に決めます。
要約チェックリスト
保存前に次を確認します。
- 外部呼び出し(
Http)または Media ファイルのインジェストがあれば、executionModeは"Async"です。 Loopbody の中に外部呼び出しを入れていません。- 外部呼び出しは 3 個以下、
SetVarは 5 個以下、全 statement は 15 個以下です。 - secret 値は
Http.headersのsecret:trueでのみ入れています。 - 取り消せない操作(外部呼び出し)はできるだけ後ろに置いています。
- update/patch の競合が心配なら
ResourceUpdateやResourcePatchのversionを使います。 - 結果を返すには
Return.valueを明示しています。
関連ドキュメント
- 値式: 値と条件のルール。
- Statement カタログ: 各文のフィールドと結果。
- クックブック: 完結した例のまとめ。
- Script リソースとエンドポイント:
Scriptリソース構造と/executeなどの HTTP エンドポイント。 - Script 概要: 最上位の構造と実行モード。
