Propagate correlation_id/causation_id through execution events, add API version header
Execution events (started/failed/succeeded) never carried the correlation/causation IDs from the ExecuteRequest, even though the fields existed on Execution. Added CausationID to ExecuteRequest and Execution, and split emitEvent into a correlated variant used throughout the execution lifecycle. handleExecute falls back to X-Correlation-ID/X-Causation-ID headers when the body omits them. Also add X-Hexis-Version negotiation on /api/v1/*, matching Nexus. Part of Vikunja #273. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018ghELqYhZNLub2TXGMazqA
This commit is contained in:
@@ -76,6 +76,7 @@ func (e *Engine) Execute(req *domain.ExecuteRequest) (*ExecuteResult, error) {
|
||||
ConfirmationID: req.ConfirmationID,
|
||||
Status: domain.ExecutionStarted,
|
||||
CorrelationID: req.CorrelationID,
|
||||
CausationID: req.CausationID,
|
||||
ResolutionEvidence: req.ResolutionEvidence,
|
||||
CreatedAt: now,
|
||||
UpdatedAt: now,
|
||||
@@ -94,7 +95,7 @@ func (e *Engine) Execute(req *domain.ExecuteRequest) (*ExecuteResult, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
e.emitEvent(domain.EventExecutionStarted, exec.ID, map[string]any{
|
||||
e.emitEventCorrelated(domain.EventExecutionStarted, exec.ID, exec.CorrelationID, exec.CausationID, map[string]any{
|
||||
"capability_id": req.CapabilityID,
|
||||
"target_entity_id": req.TargetEntityID,
|
||||
"provider": capability.Provider,
|
||||
@@ -116,7 +117,7 @@ func (e *Engine) Execute(req *domain.ExecuteRequest) (*ExecuteResult, error) {
|
||||
exec.Status = domain.ExecutionUnknown
|
||||
exec.Error = "execution timed out after " + timeout.String()
|
||||
exec.Result = map[string]any{"error": exec.Error}
|
||||
e.emitEvent(domain.EventExecutionFailed, exec.ID, map[string]any{
|
||||
e.emitEventCorrelated(domain.EventExecutionFailed, exec.ID, exec.CorrelationID, exec.CausationID, map[string]any{
|
||||
"capability_id": req.CapabilityID,
|
||||
"outcome": "unknown",
|
||||
"reason": "timeout",
|
||||
@@ -125,14 +126,14 @@ func (e *Engine) Execute(req *domain.ExecuteRequest) (*ExecuteResult, error) {
|
||||
exec.Status = domain.ExecutionFailed
|
||||
exec.Error = execErr.Error()
|
||||
exec.Result = map[string]any{"error": execErr.Error()}
|
||||
e.emitEvent(domain.EventExecutionFailed, exec.ID, map[string]any{
|
||||
e.emitEventCorrelated(domain.EventExecutionFailed, exec.ID, exec.CorrelationID, exec.CausationID, map[string]any{
|
||||
"capability_id": req.CapabilityID,
|
||||
"error": execErr.Error(),
|
||||
})
|
||||
default:
|
||||
exec.Status = domain.ExecutionSucceeded
|
||||
exec.Result = result
|
||||
e.emitEvent(domain.EventExecutionSucceeded, exec.ID, map[string]any{
|
||||
e.emitEventCorrelated(domain.EventExecutionSucceeded, exec.ID, exec.CorrelationID, exec.CausationID, map[string]any{
|
||||
"capability_id": req.CapabilityID,
|
||||
})
|
||||
}
|
||||
@@ -250,11 +251,17 @@ func (e *Engine) ValidateTarget(capabilityID, entityID string) error {
|
||||
}
|
||||
|
||||
func (e *Engine) emitEvent(evtType domain.HexisEventType, entityID string, payload map[string]any) {
|
||||
e.emitEventCorrelated(evtType, entityID, "", "", payload)
|
||||
}
|
||||
|
||||
func (e *Engine) emitEventCorrelated(evtType domain.HexisEventType, entityID, correlationID, causationID string, payload map[string]any) {
|
||||
e.store.AppendEvent(&domain.Event{
|
||||
ID: domain.NewEventID(),
|
||||
Type: evtType,
|
||||
Timestamp: time.Now().UTC(),
|
||||
Payload: payload,
|
||||
ID: domain.NewEventID(),
|
||||
Type: evtType,
|
||||
Timestamp: time.Now().UTC(),
|
||||
CorrelationID: correlationID,
|
||||
CausationID: causationID,
|
||||
Payload: payload,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user