From a6f6d3c1904db8287b80332de5c97a0163371d8e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mats=20T=C3=B6rnberg?= Date: Wed, 26 Nov 2025 19:42:45 +0100 Subject: [PATCH 1/8] add service to deployment --- deployment/deployment.yaml | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/deployment/deployment.yaml b/deployment/deployment.yaml index 3e17716..8a453f6 100644 --- a/deployment/deployment.yaml +++ b/deployment/deployment.yaml @@ -462,3 +462,14 @@ spec: value: "redis.home:6379" - name: REDIS_PASSWORD value: "slaskredis" +--- +kind: Service +apiVersion: v1 +metadata: + name: inventory +spec: + selector: + app: inventory + ports: + - name: web + port: 8080 \ No newline at end of file From 9db4abdb058decba33178b74d0108aadfd7047ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mats=20T=C3=B6rnberg?= Date: Wed, 26 Nov 2025 20:17:46 +0100 Subject: [PATCH 2/8] update service --- deployment/deployment.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deployment/deployment.yaml b/deployment/deployment.yaml index 8a453f6..7f86486 100644 --- a/deployment/deployment.yaml +++ b/deployment/deployment.yaml @@ -469,7 +469,7 @@ metadata: name: inventory spec: selector: - app: inventory + app: cart-inventory ports: - name: web port: 8080 \ No newline at end of file From 87625ffd5d2b1f411d7d30721e412ac87d3767d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mats=20T=C3=B6rnberg?= Date: Wed, 26 Nov 2025 20:29:14 +0100 Subject: [PATCH 3/8] do reservations --- cmd/cart/pool-server.go | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/cmd/cart/pool-server.go b/cmd/cart/pool-server.go index 7f0e092..c2b1f1f 100644 --- a/cmd/cart/pool-server.go +++ b/cmd/cart/pool-server.go @@ -254,7 +254,14 @@ func (s *PoolServer) AddMultipleItemHandler(w http.ResponseWriter, r *http.Reque return err } - reply, err := s.ApplyLocal(r.Context(), id, getMultipleAddMessages(r.Context(), setCartItems.Items, setCartItems.Country)...) + msgs := getMultipleAddMessages(r.Context(), setCartItems.Items, setCartItems.Country) + + err = s.HandleReservations(r.Context(), id, msgs...) + if err != nil { + return err + } + + reply, err := s.ApplyLocal(r.Context(), id, msgs...) if err != nil { return err } @@ -274,11 +281,16 @@ func (s *PoolServer) GetReservationTime(item *messages.AddItem) time.Duration { //return nil } -func (s *PoolServer) HandleReservations(ctx context.Context, cartId cart.CartId, msgs ...*messages.AddItem) error { +func (s *PoolServer) HandleReservations(ctx context.Context, cartId cart.CartId, msgs ...proto.Message) error { if s.reservationService == nil { return nil } - for _, item := range msgs { + for _, msg := range msgs { + item, ok := msg.(*messages.AddItem) + if !ok { + log.Printf("not an AddItem message, skipping reservation, was of type: %T", msg) + continue + } timeout := s.GetReservationTime(item) if timeout == 0 { continue @@ -320,8 +332,9 @@ func (s *PoolServer) AddSkuRequestHandler(w http.ResponseWriter, r *http.Request if err != nil { return err } - if s.reservationService != nil { - + err = s.HandleReservations(r.Context(), id, msg) + if err != nil { + return err } reply, err := s.ApplyLocal(r.Context(), id, msg) if err != nil { From beb03a7cd7008e8976876e07d118cf9232c2b8a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mats=20T=C3=B6rnberg?= Date: Wed, 26 Nov 2025 20:34:11 +0100 Subject: [PATCH 4/8] logs in pod --- cmd/cart/pool-server.go | 1 + 1 file changed, 1 insertion(+) diff --git a/cmd/cart/pool-server.go b/cmd/cart/pool-server.go index c2b1f1f..f9ab384 100644 --- a/cmd/cart/pool-server.go +++ b/cmd/cart/pool-server.go @@ -302,6 +302,7 @@ func (s *PoolServer) HandleReservations(ctx context.Context, cartId cart.CartId, locationId = inventory.LocationID(*item.StoreId) } span.AddEvent("reserving item", trace.WithAttributes(attribute.String("sku", item.Sku), attribute.String("locationId", string(locationId)))) + log.Printf("reserving item %s at location %s for cart %s", item.Sku, string(locationId), cartId.String()) end := time.Now().Add(timeout) err := s.reservationService.ReserveForCart(ctx, inventory.CartReserveRequest{ CartID: inventory.CartID(cartId.String()), From fac94acfe107a1a8756291c89b2c9d886af980a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mats=20T=C3=B6rnberg?= Date: Wed, 26 Nov 2025 20:35:39 +0100 Subject: [PATCH 5/8] now we should have logs! --- cmd/cart/pool-server.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/cmd/cart/pool-server.go b/cmd/cart/pool-server.go index f9ab384..c6aab31 100644 --- a/cmd/cart/pool-server.go +++ b/cmd/cart/pool-server.go @@ -80,6 +80,10 @@ func (s *PoolServer) AddSkuToCartHandler(w http.ResponseWriter, r *http.Request, if err != nil { return err } + err = s.HandleReservations(r.Context(), id, msg) + if err != nil { + return err + } data, err := s.ApplyLocal(r.Context(), id, msg) if err != nil { return err From a17d5fc5709fe12926a8e46415dc0cf69cad1c96 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mats=20T=C3=B6rnberg?= Date: Wed, 26 Nov 2025 20:42:12 +0100 Subject: [PATCH 6/8] add the reservationservice --- cmd/cart/main.go | 7 ++++++- cmd/cart/pool-server.go | 12 ++++++------ 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/cmd/cart/main.go b/cmd/cart/main.go index 7226698..e4d8192 100644 --- a/cmd/cart/main.go +++ b/cmd/cart/main.go @@ -151,7 +151,12 @@ func main() { log.Fatalf("Error creating inventory service: %v\n", err) } - syncedServer := NewPoolServer(pool, fmt.Sprintf("%s, %s", name, podIp), klarnaClient, inventoryService, rdb) + inventoryReservationService, err := inventory.NewRedisCartReservationService(rdb) + if err != nil { + log.Fatalf("Error creating inventory reservation service: %v\n", err) + } + + syncedServer := NewPoolServer(pool, fmt.Sprintf("%s, %s", name, podIp), klarnaClient, inventoryService, inventoryReservationService) app := &App{ pool: pool, diff --git a/cmd/cart/pool-server.go b/cmd/cart/pool-server.go index c6aab31..cd03c9e 100644 --- a/cmd/cart/pool-server.go +++ b/cmd/cart/pool-server.go @@ -19,7 +19,6 @@ import ( "github.com/matst80/go-redis-inventory/pkg/inventory" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" - "github.com/redis/go-redis/v9" "go.opentelemetry.io/contrib/bridges/otelslog" "go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp" "google.golang.org/protobuf/types/known/anypb" @@ -50,12 +49,13 @@ type PoolServer struct { reservationService inventory.CartReservationService } -func NewPoolServer(pool actor.GrainPool[*cart.CartGrain], pod_name string, klarnaClient *KlarnaClient, inventoryService inventory.InventoryService, inventoryRedisClient *redis.Client) *PoolServer { +func NewPoolServer(pool actor.GrainPool[*cart.CartGrain], pod_name string, klarnaClient *KlarnaClient, inventoryService inventory.InventoryService, inventoryReservationService inventory.CartReservationService) *PoolServer { srv := &PoolServer{ - GrainPool: pool, - pod_name: pod_name, - klarnaClient: klarnaClient, - inventoryService: inventoryService, + GrainPool: pool, + pod_name: pod_name, + klarnaClient: klarnaClient, + inventoryService: inventoryService, + reservationService: inventoryReservationService, } return srv From afa79e7b56cea0651559f1afd7fc6d40404f55bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mats=20T=C3=B6rnberg?= Date: Wed, 26 Nov 2025 21:35:40 +0100 Subject: [PATCH 7/8] handle limited quantity --- pkg/cart/mutation_add_item.go | 18 +++++++++++++----- pkg/cart/mutation_change_quantity.go | 13 ++++++++++--- pkg/cart/mutation_initialize_checkout.go | 9 +++++++++ 3 files changed, 32 insertions(+), 8 deletions(-) diff --git a/pkg/cart/mutation_add_item.go b/pkg/cart/mutation_add_item.go index 9b36436..0e188e3 100644 --- a/pkg/cart/mutation_add_item.go +++ b/pkg/cart/mutation_add_item.go @@ -38,16 +38,24 @@ func AddItem(g *CartGrain, m *messages.AddItem) error { if !sameStore { continue } - existing.Quantity += int(m.Quantity) + if m.ReservationEndTime != nil { + t := m.ReservationEndTime.AsTime() + if existing.ReservationEndTime == nil || existing.ReservationEndTime.Before(m.ReservationEndTime.AsTime()) { + existing.ReservationEndTime = &t + existing.Quantity = int(m.Quantity) + } else { + existing.ReservationEndTime = &t + } + + } else { + existing.Quantity += int(m.Quantity) + } existing.Stock = uint16(m.Stock) // If existing had nil store but new has one, adopt it. if existing.StoreId == nil && m.StoreId != nil { existing.StoreId = m.StoreId } - if m.ReservationEndTime != nil { - t := m.ReservationEndTime.AsTime() - existing.ReservationEndTime = &t - } + return nil } diff --git a/pkg/cart/mutation_change_quantity.go b/pkg/cart/mutation_change_quantity.go index de627ae..70e7efa 100644 --- a/pkg/cart/mutation_change_quantity.go +++ b/pkg/cart/mutation_change_quantity.go @@ -48,8 +48,15 @@ func ChangeQuantity(g *CartGrain, m *messages.ChangeQuantity) error { g.UpdateTotals() return nil } - - g.Items[foundIndex].Quantity = int(m.Quantity) - g.UpdateTotals() + item := g.Items[foundIndex] + if item == nil { + return fmt.Errorf("ChangeQuantity: item id %d not found", m.Id) + } + if item.ReservationEndTime != nil { + return fmt.Errorf("ChangeQuantity: cannot change quantity of reserved item id %d", m.Id) + } else { + item.Quantity = int(m.Quantity) + g.UpdateTotals() + } return nil } diff --git a/pkg/cart/mutation_initialize_checkout.go b/pkg/cart/mutation_initialize_checkout.go index 0e3a14f..83ebff7 100644 --- a/pkg/cart/mutation_initialize_checkout.go +++ b/pkg/cart/mutation_initialize_checkout.go @@ -2,6 +2,7 @@ package cart import ( "fmt" + "time" messages "git.k6n.net/go-cart-actor/pkg/messages" ) @@ -36,6 +37,14 @@ func InitializeCheckout(g *CartGrain, m *messages.InitializeCheckout) error { if m.OrderId == "" { return fmt.Errorf("InitializeCheckout: missing orderId") } + now := time.Now() + for _, item := range g.Items { + if item.ReservationEndTime != nil { + if now.After(*item.ReservationEndTime) { + return fmt.Errorf("InitializeCheckout: item id %d reservation has expired", item.Id) + } + } + } g.OrderReference = m.OrderId g.PaymentStatus = m.Status From 3912135b35164179659100ecd13e156aaeb2cd9d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mats=20T=C3=B6rnberg?= Date: Wed, 26 Nov 2025 21:43:18 +0100 Subject: [PATCH 8/8] update --- pkg/cart/mutation_add_item.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/cart/mutation_add_item.go b/pkg/cart/mutation_add_item.go index 0e188e3..1269d58 100644 --- a/pkg/cart/mutation_add_item.go +++ b/pkg/cart/mutation_add_item.go @@ -42,7 +42,7 @@ func AddItem(g *CartGrain, m *messages.AddItem) error { t := m.ReservationEndTime.AsTime() if existing.ReservationEndTime == nil || existing.ReservationEndTime.Before(m.ReservationEndTime.AsTime()) { existing.ReservationEndTime = &t - existing.Quantity = int(m.Quantity) + existing.Quantity += int(m.Quantity) } else { existing.ReservationEndTime = &t }