diff --git a/kubernetes-manifests/cartservice.yaml b/kubernetes-manifests/cartservice.yaml
new file mode 100644
index 0000000..83cb82d
--- /dev/null
+++ b/kubernetes-manifests/cartservice.yaml
@@ -0,0 +1,39 @@
+apiVersion: extensions/v1beta1
+kind: Deployment
+metadata:
+ name: cartservice
+spec:
+ template:
+ metadata:
+ labels:
+ app: cartservice
+ spec:
+ containers:
+ - name: server
+ image: cartservice
+ ports:
+ - containerPort: 7070
+ env:
+ - name: REDIS_ADDR
+ value: "redis-cart:6379"
+ - name: CART_SERVICE_PORT
+ value: "7070"
+ resources:
+ requests:
+ cpu: 200m
+ memory: 64Mi
+ limits:
+ cpu: 300m
+ memory: 128Mi
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: cartservice
+spec:
+ type: ClusterIP
+ selector:
+ app: cartservice
+ ports:
+ - port: 7070
+ targetPort: 7070
diff --git a/kubernetes-manifests/checkoutservice.yaml b/kubernetes-manifests/checkoutservice.yaml
index 0c05a5c..5bc6ec9 100644
--- a/kubernetes-manifests/checkoutservice.yaml
+++ b/kubernetes-manifests/checkoutservice.yaml
@@ -25,7 +25,7 @@ spec:
- name: CURRENCY_SERVICE_ADDR
value: "currencyservice:7000"
- name: CART_SERVICE_ADDR
- value: "cartservice:9999"
+ value: "cartservice:7070"
resources:
requests:
cpu: 100m
diff --git a/skaffold.yaml b/skaffold.yaml
index 9f37978..366200c 100644
--- a/skaffold.yaml
+++ b/skaffold.yaml
@@ -16,6 +16,8 @@ build:
workspace: src/paymentservice
- imageName: currencyservice
workspace: src/currencyservice
+ - imageName: cartservice
+ workspace: src/cartservice
deploy:
kubectl:
manifests:
diff --git a/src/frontend/handlers.go b/src/frontend/handlers.go
index 410dd7c..e0893f8 100644
--- a/src/frontend/handlers.go
+++ b/src/frontend/handlers.go
@@ -43,15 +43,20 @@ func ensureSessionID(next http.HandlerFunc) http.HandlerFunc {
}
func (fe *frontendServer) homeHandler(w http.ResponseWriter, r *http.Request) {
- log.Printf("[home] session_id=%+v", r.Context().Value(ctxKeySessionID{}))
+ log.Printf("[home] session_id=%+v", sessionID(r))
currencies, err := fe.getCurrencies(r.Context())
if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
+ http.Error(w, fmt.Sprintf("could not retrieve currencies: %+v", err), http.StatusInternalServerError)
return
}
products, err := fe.getProducts(r.Context())
if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
+ http.Error(w, fmt.Sprintf("could not retrieve products: %+v", err), http.StatusInternalServerError)
+ return
+ }
+ cart, err := fe.getCart(r.Context(), sessionID(r))
+ if err != nil {
+ http.Error(w, fmt.Sprintf("could not retrieve cart: %+v", err), http.StatusInternalServerError)
return
}
@@ -76,7 +81,8 @@ func (fe *frontendServer) homeHandler(w http.ResponseWriter, r *http.Request) {
"user_currency": currentCurrency(r),
"currencies": currencies,
"products": ps,
- "session_id": r.Context().Value(ctxKeySessionID{}),
+ "session_id": sessionID(r),
+ "cart_size": len(cart),
}); err != nil {
log.Println(err)
}
@@ -97,7 +103,7 @@ func (fe *frontendServer) productHandler(w http.ResponseWriter, r *http.Request)
currencies, err := fe.getCurrencies(r.Context())
if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
+ http.Error(w, fmt.Sprintf("could not retrieve currencies: %+v", err), http.StatusInternalServerError)
return
}
@@ -118,14 +124,14 @@ func (fe *frontendServer) productHandler(w http.ResponseWriter, r *http.Request)
"user_currency": currentCurrency(r),
"currencies": currencies,
"product": product,
- "session_id": r.Context().Value(ctxKeySessionID{}),
+ "session_id": sessionID(r),
}); err != nil {
log.Println(err)
}
}
func (fe *frontendServer) logoutHandler(w http.ResponseWriter, r *http.Request) {
- log.Printf("[home] session_id=%+v", r.Context().Value(ctxKeySessionID{}))
+ log.Printf("[home] session_id=%+v", sessionID(r))
for _, c := range r.Cookies() {
c.Expires = time.Now().Add(-time.Hour * 24 * 365)
c.MaxAge = -1
@@ -137,7 +143,7 @@ func (fe *frontendServer) logoutHandler(w http.ResponseWriter, r *http.Request)
func (fe *frontendServer) setCurrencyHandler(w http.ResponseWriter, r *http.Request) {
cur := r.FormValue("currency_code")
- log.Printf("[setCurrency] session_id=%+v code=%s", r.Context().Value(ctxKeySessionID{}), cur)
+ log.Printf("[setCurrency] session_id=%+v code=%s", sessionID(r), cur)
if cur != "" {
http.SetCookie(w, &http.Cookie{
Name: cookieCurrency,
@@ -160,3 +166,11 @@ func currentCurrency(r *http.Request) string {
}
return defaultCurrency
}
+
+func sessionID(r *http.Request) string {
+ v := r.Context().Value(ctxKeySessionID{})
+ if v != nil {
+ return v.(string)
+ }
+ return ""
+}
diff --git a/src/frontend/main.go b/src/frontend/main.go
index 4ca4d03..6b3584d 100644
--- a/src/frontend/main.go
+++ b/src/frontend/main.go
@@ -50,7 +50,7 @@ func main() {
svc := new(frontendServer)
mustMapEnv(&svc.productCatalogSvcAddr, "PRODUCT_CATALOG_SERVICE_ADDR")
mustMapEnv(&svc.currencySvcAddr, "CURRENCY_SERVICE_ADDR")
- // mustMapEnv(&svc.cartSvcAddr, "CART_SERVICE_ADDR")
+ mustMapEnv(&svc.cartSvcAddr, "CART_SERVICE_ADDR")
var err error
svc.currencySvcConn, err = grpc.DialContext(ctx, svc.currencySvcAddr, grpc.WithInsecure())
@@ -61,6 +61,10 @@ func main() {
if err != nil {
log.Fatalf("failed to connect productcatalog service: %+v", err)
}
+ svc.cartSvcConn, err = grpc.DialContext(ctx, svc.cartSvcAddr, grpc.WithInsecure())
+ if err != nil {
+ log.Fatalf("failed to connect cart service at %s: %+v", svc.cartSvcAddr, err)
+ }
r := mux.NewRouter()
r.HandleFunc("/", ensureSessionID(svc.homeHandler)).Methods(http.MethodGet, http.MethodHead)
diff --git a/src/frontend/rpc.go b/src/frontend/rpc.go
index 1a08956..54c32bf 100644
--- a/src/frontend/rpc.go
+++ b/src/frontend/rpc.go
@@ -3,7 +3,11 @@ package main
import (
"context"
+ "google.golang.org/grpc/codes"
+
pb "frontend/genproto"
+
+ "google.golang.org/grpc/status"
)
const (
@@ -37,6 +41,15 @@ func (fe *frontendServer) getProduct(ctx context.Context, id string) (*pb.Produc
return resp, err
}
+func (fe *frontendServer) getCart(ctx context.Context, userID string) ([]*pb.CartItem, error) {
+ resp, err := pb.NewCartServiceClient(fe.cartSvcConn).GetCart(ctx, &pb.GetCartRequest{UserId: userID})
+ if status.Code(err) == codes.Canceled {
+ // TODO(ahmetb) remove this workaround when cartservice returns ok response to GetCart() with non-existing users
+ return nil, nil
+ }
+ return resp.GetItems(), err
+}
+
func (fe *frontendServer) convertCurrency(ctx context.Context, money *pb.Money, currency string) (*pb.Money, error) {
if avoidNoopCurrencyConversionRPC && money.GetCurrencyCode() == currency {
return money, nil
diff --git a/src/frontend/templates/header.html b/src/frontend/templates/header.html
index 5b4110f..51ba64b 100644
--- a/src/frontend/templates/header.html
+++ b/src/frontend/templates/header.html
@@ -23,7 +23,7 @@
{{end}}
- View Cart
+ View Cart ({{$.cart_size}})
diff --git a/src/test-cli/main.go b/src/test-cli/main.go
index 25bab2c..b66503b 100644
--- a/src/test-cli/main.go
+++ b/src/test-cli/main.go
@@ -299,8 +299,16 @@ func testCartService() error {
defer conn.Close()
cl := pb.NewCartServiceClient(conn)
- log.Println("--- rpc AddItem()")
userID := "smoke-test-user"
+ log.Println("--- rpc GetCart()")
+ cartResp, err := cl.GetCart(context.TODO(), &pb.GetCartRequest{
+ UserId: userID})
+ if err != nil {
+ return err
+ }
+ log.Printf("--> %d items in cart for user %q", len(cartResp.Items), cartResp.UserId)
+
+ log.Println("--- rpc AddItem()")
_, err = cl.AddItem(context.TODO(), &pb.AddItemRequest{
UserId: userID,
Item: &pb.CartItem{ProductId: "1", Quantity: 2},
@@ -319,14 +327,13 @@ func testCartService() error {
log.Printf("--> added item")
log.Println("--- rpc GetCart()")
- cartResp, err := cl.GetCart(context.TODO(), &pb.GetCartRequest{
+ cartResp, err = cl.GetCart(context.TODO(), &pb.GetCartRequest{
UserId: userID})
if err != nil {
return err
}
log.Printf("--> %d items in cart for user %q", len(cartResp.Items), cartResp.UserId)
log.Printf("--> cart: %v", cartResp.Items)
-
log.Println("--- rpc EmptyCart()")
_, err = cl.EmptyCart(context.TODO(), &pb.EmptyCartRequest{
UserId: userID})