diff --git a/.env b/.env index 1e3f671459..d84d30d370 100644 --- a/.env +++ b/.env @@ -47,7 +47,9 @@ SHIPPING_SERVICE_PORT=50050 SHIPPING_SERVICE_ADDR=shippingservice:${SHIPPING_SERVICE_PORT} FEATURE_FLAG_SERVICE_PORT=8081 +FEATURE_FLAG_SERVICE_ADDR=featureflagservice:${FEATURE_FLAG_SERVICE_PORT} FEATURE_FLAG_GRPC_SERVICE_PORT=50053 +FEATURE_FLAG_GRPC_SERVICE_ADDR=featureflagservice:${FEATURE_FLAG_GRPC_SERVICE_PORT} # Prometheus PROMETHEUS_SERVICE_PORT=9090 diff --git a/CHANGELOG.md b/CHANGELOG.md index b84b7a0d7c..15535da270 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -69,4 +69,7 @@ significant modifications will be credited to OpenTelemetry Authors. ([#290](https://github.com/open-telemetry/opentelemetry-demo/pull/290)) * Added Frontend [Cypress](https://www.cypress.io/) E2E tests ([#298](https://github.com/open-telemetry/opentelemetry-demo/pull/298)) -* Added baggage support in CurrencyService [#281](https://github.com/open-telemetry/opentelemetry-demo/pull/281) +* Added baggage support in CurrencyService +([#281](https://github.com/open-telemetry/opentelemetry-demo/pull/281)) +* Added error for a specific product based on a feature flag +([#245](https://github.com/open-telemetry/opentelemetry-demo/pull/245)) diff --git a/docker-compose.yml b/docker-compose.yml index fb478a6d6c..8db634ca66 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -255,6 +255,7 @@ services: - "${PRODUCT_CATALOG_SERVICE_PORT}" environment: - PRODUCT_CATALOG_SERVICE_PORT + - FEATURE_FLAG_GRPC_SERVICE_ADDR - OTEL_EXPORTER_OTLP_TRACES_ENDPOINT - OTEL_SERVICE_NAME=productcatalogservice depends_on: diff --git a/src/productcatalogservice/server.go b/src/productcatalogservice/server.go index 6ad027febc..70b2285741 100644 --- a/src/productcatalogservice/server.go +++ b/src/productcatalogservice/server.go @@ -18,6 +18,7 @@ import ( "context" "flag" "fmt" + "google.golang.org/grpc/credentials/insecure" "io/ioutil" "net" "os" @@ -150,6 +151,7 @@ func run(port string) string { ) svc := &productCatalog{} + mustMapEnv(&svc.featureFlagSvcAddr, "FEATURE_FLAG_GRPC_SERVICE_ADDR") pb.RegisterProductCatalogServiceServer(srv, svc) healthpb.RegisterHealthServer(srv, svc) @@ -158,6 +160,7 @@ func run(port string) string { } type productCatalog struct { + featureFlagSvcAddr string pb.UnimplementedProductCatalogServiceServer } @@ -223,6 +226,15 @@ func (p *productCatalog) GetProduct(ctx context.Context, req *pb.GetProductReque ) time.Sleep(extraLatency) + + // conditional break if feature flag is enabled on a specific product + if p.checkProductFailure(ctx, req.Id) { + msg := fmt.Sprintf("interal error: product catalog feature flag for failure is enabled") + span.SetStatus(otelcodes.Error, msg) + span.AddEvent(msg) + return nil, status.Errorf(codes.Internal, msg) + } + var found *pb.Product for i := 0; i < len(parseCatalog()); i++ { if req.Id == parseCatalog()[i].Id { @@ -261,3 +273,40 @@ func (p *productCatalog) SearchProducts(ctx context.Context, req *pb.SearchProdu ) return &pb.SearchProductsResponse{Results: ps}, nil } + +func (p *productCatalog) checkProductFailure(ctx context.Context, id string) bool { + + if id == "OLJCESPC7Z" { + conn, err := createClient(ctx, p.featureFlagSvcAddr) + if err != nil { + //report the error but don't fail + span := trace.SpanFromContext(ctx) + span.AddEvent("error", trace.WithAttributes(attribute.String("message", "failed to connect to feature flag service"))) + return false + } + defer conn.Close() + + ffResponse, err := pb.NewFeatureFlagServiceClient(conn).GetFlag(ctx, &pb.GetFlagRequest{ + Name: "productCatalogFailure", + }) + if err != nil { + span := trace.SpanFromContext(ctx) + span.AddEvent("error", trace.WithAttributes(attribute.String("message", "failed to retrieve product catalog feature flag"))) + return false + } + + if ffResponse.GetFlag().Enabled { + return true + } + + } + return false +} + +func createClient(ctx context.Context, svcAddr string) (*grpc.ClientConn, error) { + return grpc.DialContext(ctx, svcAddr, + grpc.WithTransportCredentials(insecure.NewCredentials()), + grpc.WithUnaryInterceptor(otelgrpc.UnaryClientInterceptor()), + grpc.WithStreamInterceptor(otelgrpc.StreamClientInterceptor()), + ) +}