order sagas
Build and Publish / BuildAndDeployArm64 (push) Failing after 5s
Build and Publish / BuildAndDeployAmd64 (push) Has been cancelled

This commit is contained in:
2026-06-21 11:33:20 +02:00
parent 484f2364fb
commit 1a365de071
25 changed files with 4224 additions and 1 deletions
+58
View File
@@ -0,0 +1,58 @@
package order
import (
"context"
"encoding/json"
"fmt"
"git.k6n.net/mats/go-cart-actor/pkg/flow"
)
// Publisher is the minimal seam the amqp_emit hook needs. cmd/order supplies a
// RabbitMQ-backed implementation; tests pass a fake. Keeping it an interface
// keeps pkg/order free of an AMQP dependency.
type Publisher interface {
Publish(exchange, routingKey string, body []byte) error
}
// RegisterEmitHook registers the "amqp_emit" flow hook, which publishes a flow
// event to a message broker — the bridge from a saga step to other services
// (loyalty, ERP sync, notifications) without coupling the flow to them. It is
// the commerce analogue of the CMS event listeners. Params (optional):
//
// {"exchange": "", "routingKey": "order-events"}
//
// The body is {step, phase, id, error, vars}. With a nil publisher the hook is
// still registered (so the editor lists it) but errors at run time — and since
// hook errors never abort a flow, that failure is logged, not fatal.
func RegisterEmitHook(reg *flow.Registry, pub Publisher) {
reg.Hook("amqp_emit", func(_ context.Context, st *flow.State, info flow.HookInfo, params json.RawMessage) error {
if pub == nil {
return fmt.Errorf("amqp_emit: no publisher configured")
}
var p struct {
Exchange string `json:"exchange"`
RoutingKey string `json:"routingKey"`
}
if len(params) > 0 {
if err := json.Unmarshal(params, &p); err != nil {
return fmt.Errorf("amqp_emit: bad params: %w", err)
}
}
if p.RoutingKey == "" {
p.RoutingKey = "order-events"
}
errStr := ""
if info.Err != nil {
errStr = info.Err.Error()
}
body, _ := json.Marshal(map[string]any{
"step": info.Step,
"phase": info.Phase,
"id": st.ID,
"error": errStr,
"vars": st.Vars,
})
return pub.Publish(p.Exchange, p.RoutingKey, body)
})
}