all the refactor
Build and Publish / BuildAndDeployAmd64 (push) Failing after 5s
Build and Publish / BuildAndDeployArm64 (push) Failing after 6s

This commit is contained in:
2026-06-28 17:51:52 +02:00
parent 7db0d236c7
commit aa8b2bdedc
84 changed files with 4328 additions and 2344 deletions
+54 -5
View File
@@ -3,6 +3,7 @@ package main
import (
"context"
"encoding/json"
"fmt"
"io"
"log"
"net/http"
@@ -41,12 +42,19 @@ var (
type PoolServer struct {
actor.GrainPool[cart.CartGrain]
pod_name string
// idx is the bus-fed catalog projection cache, consulted at HTTP-fetch
// sites (AddSkuToCartHandler, buildItemGroups) to overlay authoritative
// price / tax_class / display fields onto AddItem before mutation. nil is
// tolerated so handlers still serve if the bus consumer is unavailable
// (orphan / quarantine / CI), with a plain cache-miss fall-through.
idx *catalogProjectionCache
}
func NewPoolServer(pool actor.GrainPool[cart.CartGrain], pod_name string) *PoolServer {
func NewPoolServer(pool actor.GrainPool[cart.CartGrain], pod_name string, idx *catalogProjectionCache) *PoolServer {
srv := &PoolServer{
GrainPool: pool,
pod_name: pod_name,
idx: idx,
}
return srv
@@ -67,10 +75,26 @@ func (s *PoolServer) GetCartHandler(w http.ResponseWriter, r *http.Request, id c
func (s *PoolServer) AddSkuToCartHandler(w http.ResponseWriter, r *http.Request, id cart.CartId) error {
sku := r.PathValue("sku")
if s.idx != nil && s.idx.IsDeleted(sku) {
// Bus-deleted SKU — skip the HTTP fetch and reject the add. Mirrors the
// product-fetcher's "product service returned %d for sku %s" shape so
// upstream code that pattern-matches that string still works, AND we
// publish StatusNotFound so the HTTP response carries the right code
// (the handler's error-return path otherwise renders as 500).
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(http.StatusNotFound)
_, _ = w.Write([]byte(fmt.Sprintf(`{"error":"product service returned %d for sku %s (bus-deleted)","sku":%q}`, 404, sku, sku)))
return nil
}
msg, err := GetItemAddMessage(r.Context(), sku, 1, getCountryFromHost(r.Host), nil)
if err != nil {
return err
}
if s.idx != nil {
if p, ok := s.idx.Get(sku); ok {
ApplyProjectionOverlay(msg, p)
}
}
data, err := s.ApplyLocal(r.Context(), id, msg)
if err != nil {
@@ -154,16 +178,32 @@ type itemGroup struct {
// drive child pricing, then children are fetched concurrently. Input order is
// preserved. Items that fail to fetch are skipped (logged), matching the prior
// best-effort behavior.
func buildItemGroups(ctx context.Context, items []Item, country string) []itemGroup {
//
// idx is the bus-fed projection cache; when non-nil, every AddItem built here
// has its cache-covered fields (price/tax_class/display/inventory_tracked/
// drop_ship) overlaid onto the HTTP-fetched answer. Cache-hit calls naturally
// become authoritative for what the projection carries; HTTP stays for
// dimensions (parent width/height for child pricing), seller/orgPrice and the
// dynamic ExtraJson product data. Skipped cleanly when idx is nil.
func buildItemGroups(ctx context.Context, items []Item, country string, idx *catalogProjectionCache) []itemGroup {
groups := make([]itemGroup, len(items))
wg := sync.WaitGroup{}
for i, itm := range items {
wg.Go(func() {
if idx != nil && idx.IsDeleted(itm.Sku) {
log.Printf("error adding item %s: bus-deleted (skipping)", itm.Sku)
return
}
parentMsg, parentProduct, err := BuildItemMessage(ctx, itm.Sku, itm.Quantity, country, itm.StoreId, nil)
if err != nil {
log.Printf("error adding item %s: %v", itm.Sku, err)
return
}
if idx != nil {
if p, ok := idx.Get(itm.Sku); ok {
ApplyProjectionOverlay(parentMsg, p)
}
}
parentMsg.CustomFields = itm.CustomFields
groups[i].parent = parentMsg
@@ -174,11 +214,20 @@ func buildItemGroups(ctx context.Context, items []Item, country string) []itemGr
cwg := sync.WaitGroup{}
for j, child := range itm.Children {
cwg.Go(func() {
if idx != nil && idx.IsDeleted(child.Sku) {
log.Printf("error adding child %s of %s: bus-deleted (skipping)", child.Sku, itm.Sku)
return
}
childMsg, _, err := BuildItemMessage(ctx, child.Sku, child.Quantity, country, child.StoreId, parentProduct)
if err != nil {
log.Printf("error adding child %s of %s: %v", child.Sku, itm.Sku, err)
return
}
if idx != nil {
if p, ok := idx.Get(child.Sku); ok {
ApplyProjectionOverlay(childMsg, p)
}
}
childMsg.CustomFields = child.CustomFields
children[j] = childMsg
})
@@ -263,7 +312,7 @@ func (s *PoolServer) SetCartItemsHandler(w http.ResponseWriter, r *http.Request,
if _, err := s.ApplyLocal(r.Context(), id, &messages.ClearCartRequest{}); err != nil {
return err
}
groups := buildItemGroups(r.Context(), setCartItems.Items, setCartItems.Country)
groups := buildItemGroups(r.Context(), setCartItems.Items, setCartItems.Country, s.idx)
reply, err := s.applyItemGroups(r.Context(), id, groups)
if err != nil {
return err
@@ -286,7 +335,7 @@ func (s *PoolServer) AddMultipleItemHandler(w http.ResponseWriter, r *http.Reque
return err
}
groups := buildItemGroups(r.Context(), setCartItems.Items, setCartItems.Country)
groups := buildItemGroups(r.Context(), setCartItems.Items, setCartItems.Country, s.idx)
reply, err := s.applyItemGroups(r.Context(), id, groups)
if err != nil {
return err
@@ -326,7 +375,7 @@ func (s *PoolServer) AddSkuRequestHandler(w http.ResponseWriter, r *http.Request
Children: addRequest.Children,
CustomFields: addRequest.CustomFields,
}
groups := buildItemGroups(r.Context(), []Item{item}, addRequest.Country)
groups := buildItemGroups(r.Context(), []Item{item}, addRequest.Country, s.idx)
reply, err := s.applyItemGroups(r.Context(), id, groups)
if err != nil {
return err