原子資料集發布
Publish session 是給「整份資料必須一次對讀者可見」的批次通道。Moderator 先開啟 session,把一個或多個經驗證的 chunk 暫存到所有 record read 都看不到的區域,再派送 commit。Commit 會在同一個資料庫 transaction 裡軟刪除選填的 replace 集合,並新增所有 staged rows:不是完整新資料集一次落地,就是讀者繼續看到完整舊資料集。
這不是 bulk-insert、bulk-update、bulk-delete 的部分成功語意。三種保證的並排比較見批次操作。
Scope 與權限
Publish session 只存在於 department 與 company table:
| Scope | Base path |
|---|---|
| Department | /private/module/custom_tables/department/{department_id}/tables/{table_id}/publish-sessions |
| Company | /private/module/custom_tables/company/tables/{table_id}/publish-sessions |
沒有 chatroom 路由。每個操作都要求目前仍具 table moderator 權限。開啟 session 的 moderator 擁有變更權:只有他能 stage chunk、commit 或 abort;任何目前的 moderator 都能讀取 status,讓共同管理者看出是誰占用 active publish slot,以及 commit 為何失敗。
資料表帶有 require_approval 或 channel 規則時不能開啟 session。Publish commit 無法先 hold 等待日後覆核,而 background worker 也沒有 acting chatroom 可通過 channel floor。
1. 開啟唯一 session
對 department 或 company base path 送出相同 payload:
{
"idempotency_key": "catalog-2026-08-20",
"replace_filter": [
{
"column": "col_55555555_5555_4555_8555_555555555555",
"op": "eq",
"value": "current"
}
]
}兩個欄位都可省略。replace_filter 省略或為空時是 append-only publish;提供時最多包含 20 個已儲存欄位條件,並使用內部欄位鍵。Server 會在開啟時立即編譯,因此未知或 computed column 會在任何資料暫存前就失敗。
idempotency_key 最長 128 字。對同一張表與同一位 actor,只要原 session 尚未過期,且狀態為 open、committing 或 committed,以同一 key 重送就會回傳原 session 並標記 replayed: true,不會再開一個。已 aborted 的 session 即使原 expiry 尚未到,也不會被重播。
{
"session_id": "33333333-3333-4333-8333-333333333333",
"expires_at": "2026-08-21T00:00:00Z",
"replayed": false
}硬性到期時間是建立後 24 小時。每張表同一時間只能有一個 open 或 committing session;在 owner abort、session 過期,或 commit 完成釋放 slot 之前,第二次開啟會收到 409 session_conflict。
2. 暫存可安全重試的 chunks
每個 chunk 送到:
POST {base}/publish-sessions/{session_id}/chunks{
"seq": 0,
"records": [
{ "訂單編號": "A-1001", "狀態": "current" },
{ "訂單編號": "A-1002", "狀態": "current" }
]
}Chunk contract 有明確上限:
seq是0到63的整數。- 每個 chunk 可放 1–5,000 列;整個 session 的所有 sequence slots 合計最多 5,000 staged rows。
- 每列使用一般 create body shape:顯示名稱或內部鍵,以及單筆建立路徑接受的 link 與 attachment shape。不要送
id。Validator 內部可能暫用一個 ID,但真實 record ID 只由 commit 的 create path 產生。 - 重送既有
seq會原子取代該整個 chunk。遇到回應不明時請重用同一 sequence number,不要以新號碼附加一份重複資料。 - Schema validation 與 advisory rule precheck 會檢查完整 chunk;任一列失敗,整個 chunk 都拒絕,回傳 zero-based
row_indexerrors,原本該 slot 的內容保持不變。
接受的列只存在 staging table。一般 record list、search、saved view、public read、callback 與 agent tool 都看不到。成功回應的 accepted count 與 staged_total 只代表已暫存,不代表已發布。
3. 派送原子 commit
確認 staged_count 後呼叫:
POST {base}/publish-sessions/{session_id}/commitSession 必須是 open,且至少已有一列。成功回應是非同步派送:
{
"ticket_id": "44444444-4444-4444-8444-444444444444",
"replayed": false
}這不代表 commit 已完成。Session 已是 committing 或 committed 時重試,只會回既有 ticket 並標記 replayed: true,絕不重複派送同一次 commit。
Worker 會在一個 transaction 內完成整次 flip:
- 重新載入並鎖住 session 與 table,重新檢查 opener 現在的權限。
- 若有
replace_filter,將它與 opener 目前的 row ACL 及 scope floor 以 AND 合併;不在授權集合內的列永遠不會成為刪除目標。 - Live replacement set 最多 5,000 列。更廣的結果會以
replace_target_cap_exceeded失敗;請縮小 filter 或拆分發布。 - 經由真正的 delete core 軟刪除所有獲授權 replacement rows。
- 經由真正的 create core 新增全部 staged rows,包括 schema、rules、links、attachments 與 scope enforcement。
- 只 commit 一次,接著清掉 staging 並把 session 標為
committed。
最後 commit 前的任何失敗都會回滾完整 flip。讀者永遠看不到刪到一半或新增到一半的資料集。
同時輪詢兩個來源
以 generic task ticket 追蹤 worker 進度:
GET /public/task/{ticket_id}並同時讀取 session:
GET {base}/publish-sessions/{session_id}Generic ticket 告訴你 background work 是 submitting、processing、completed 或 failed。Session 則提供 publish lifecycle(open、committing、committed、aborted、expired)、staged count、到期時間、ticket、replace filter 與最近一次 structured commit error。共同 moderator 可以讀這份 status,但不能變更 session。
在不暴露部分資料的前提下重試或放棄
可重試的 validation、row、link、permission 或 rule 失敗會回滾 transaction、記錄 structured error、讓 session 回到 open,並保留所有 chunks。請以相同 seq 重送來修正 staged chunk,或修好 live dependency,再次 commit;新的 attempt 會得到新 ticket。不要只看 generic ticket failed 就認定 session 已中止,必須讀 session status。
Table 消失、table/company identity 不一致或 session 過期時,session 會進入 terminal 狀態並清掉 staging,不會重新開啟。失去 moderator authority 不同:該次 commit 會以 actor_not_authorized 重新開啟 session 並保留 staging,直到 owner 恢復權限或 abort。Session 一旦 committed,就沒有 publish-session rollback;被軟刪除的舊列改走一般 record history 與 restore 語意。
若要放棄尚未 commit 的發布,由 owner 呼叫:
POST {base}/publish-sessions/{session_id}/abort只有 open session 可以 abort。它會刪除所有 staged rows 並釋放 active slot;已進入 committing 的 commit 不能在這裡取消,已完成的 commit 也不能靠 abort 還原。
Client checklist
- 只在 department/company table 且確實需要一次可見時使用這條 lane。
- 將 open 回應的
session_id、expires_at與穩定 idempotency key 一起保存。 - 以 deterministic 方式編號 chunks;回應不明時用相同
seq重試。 - 絕不提供 record IDs,讓 commit 產生它們。
- Commit 前先確認 status 的
staged_count。 - 把 commit
200視為派送,接著同時輪詢 task 與 session。 - 可重試失敗時修復或取代問題 chunk 再 commit;確定放棄時趁 session 仍 open 執行 abort。
Endpoint 卡片與精確 request/response models 見批次操作參考。