docs: add eventual-consistency annotations

D-03: document non-transactional boundaries.

- Comment in platform_webhook_handler.go explaining that dialog.Process
  and outbox.InsertPendingBatch are not in a single transaction; 500 is
  returned on outbox failure for caller retry.
- Package-level comment in dialog/service.go noting the lack of a unified
  transactional outer box and the eventually-consistent nature of storage
  operations.
This commit is contained in:
Your Name
2026-05-11 13:10:03 +08:00
parent 22384d155b
commit 771304eabe
2 changed files with 18 additions and 0 deletions

View File

@@ -88,6 +88,13 @@ func (h *PlatformWebhookHandler) Handle(w http.ResponseWriter, r *http.Request)
writeJSON(w, http.StatusInternalServerError, map[string]any{"error": map[string]any{"code": cserrors.CS_SYS_5001, "message": cserrors.ErrorMsg(cserrors.CS_SYS_5001)}}) writeJSON(w, http.StatusInternalServerError, map[string]any{"error": map[string]any{"code": cserrors.CS_SYS_5001, "message": cserrors.ErrorMsg(cserrors.CS_SYS_5001)}})
return return
} }
// NOTE: Final-consistency boundary.
// dialog.Process and outbox.InsertPendingBatch are NOT enclosed in a single
// transaction. If outbox insertion fails after dialog succeeds, the business
// state (Session/Ticket/Audit) is already persisted but no downstream event
// is emitted. In that case we return HTTP 500 so the platform caller can
// retry; DedupRepository.TryRecord inside dialog.Process guards against
// duplicate business-state mutations on retry.
if h.eventWriter == nil { if h.eventWriter == nil {
writeJSON(w, http.StatusInternalServerError, map[string]any{"error": map[string]any{"code": cserrors.CS_SYS_5001, "message": cserrors.ErrorMsg(cserrors.CS_SYS_5001)}}) writeJSON(w, http.StatusInternalServerError, map[string]any{"error": map[string]any{"code": cserrors.CS_SYS_5001, "message": cserrors.ErrorMsg(cserrors.CS_SYS_5001)}})
return return

View File

@@ -1,3 +1,14 @@
// Package dialog implements the core message-processing service.
//
// NOTE on transaction boundaries: the current repository layer does not
// provide a unified transactional outer box (UnitOfWork / sql.Tx). Each
// repository call (SessionRepository, DedupRepository, TicketRepository,
// AuditRepository) executes on its own connection. Therefore the operations
// inside Process are eventually-consistent rather than strictly atomic.
//
// A future refactor introducing UnitOfWork or TxProvider could lift this
// limitation and wrap the entire flow plus outbox insertion in a single
// transaction.
package dialog package dialog
import ( import (