all the refactor
This commit is contained in:
+54
-5
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user