summaryrefslogtreecommitdiff
path: root/src/recommendation
diff options
context:
space:
mode:
Diffstat (limited to 'src/recommendation')
-rw-r--r--src/recommendation/Dockerfile30
-rw-r--r--src/recommendation/README.md20
-rw-r--r--src/recommendation/demo_pb2.py130
-rw-r--r--src/recommendation/demo_pb2_grpc.py1005
-rw-r--r--src/recommendation/genproto/Dockerfile8
-rw-r--r--src/recommendation/logger.py28
-rw-r--r--src/recommendation/metrics.py17
-rw-r--r--src/recommendation/recommendation_server.py173
-rw-r--r--src/recommendation/requirements.txt8
9 files changed, 1419 insertions, 0 deletions
diff --git a/src/recommendation/Dockerfile b/src/recommendation/Dockerfile
new file mode 100644
index 0000000..757b5f0
--- /dev/null
+++ b/src/recommendation/Dockerfile
@@ -0,0 +1,30 @@
+# Copyright The OpenTelemetry Authors
+# SPDX-License-Identifier: Apache-2.0
+
+
+FROM docker.io/library/python:3.12-alpine3.22 AS build-venv
+
+RUN apk update && \
+ apk add gcc g++ linux-headers
+
+COPY ./src/recommendation/requirements.txt requirements.txt
+
+RUN python -m venv venv && \
+ venv/bin/pip install --no-cache-dir -r requirements.txt
+
+RUN venv/bin/opentelemetry-bootstrap -a install
+
+FROM docker.io/library/python:3.12-alpine3.22
+
+COPY --from=build-venv /venv/ /venv/
+
+WORKDIR /app
+
+COPY ./src/recommendation/demo_pb2_grpc.py demo_pb2_grpc.py
+COPY ./src/recommendation/demo_pb2.py demo_pb2.py
+COPY ./src/recommendation/logger.py logger.py
+COPY ./src/recommendation/metrics.py metrics.py
+COPY ./src/recommendation/recommendation_server.py recommendation_server.py
+
+EXPOSE ${RECOMMENDATION_PORT}
+ENTRYPOINT [ "/venv/bin/opentelemetry-instrument", "/venv/bin/python", "recommendation_server.py" ]
diff --git a/src/recommendation/README.md b/src/recommendation/README.md
new file mode 100644
index 0000000..ec0df48
--- /dev/null
+++ b/src/recommendation/README.md
@@ -0,0 +1,20 @@
+# Recommendation Service
+
+This service provides recommendations for other products based on the currently
+selected product.
+
+## Local Build
+
+To build the protos, run from the root directory:
+
+```sh
+make docker-generate-protobuf
+```
+
+## Docker Build
+
+From the root directory, run:
+
+```sh
+docker compose build recommendation
+```
diff --git a/src/recommendation/demo_pb2.py b/src/recommendation/demo_pb2.py
new file mode 100644
index 0000000..119dfb9
--- /dev/null
+++ b/src/recommendation/demo_pb2.py
@@ -0,0 +1,130 @@
+# -*- coding: utf-8 -*-
+# Generated by the protocol buffer compiler. DO NOT EDIT!
+# source: demo.proto
+"""Generated protocol buffer code."""
+from google.protobuf import descriptor as _descriptor
+from google.protobuf import descriptor_pool as _descriptor_pool
+from google.protobuf import symbol_database as _symbol_database
+from google.protobuf.internal import builder as _builder
+# @@protoc_insertion_point(imports)
+
+_sym_db = _symbol_database.Default()
+
+
+
+
+DESCRIPTOR = _descriptor_pool.Default().AddSerializedFile(b'\n\ndemo.proto\x12\x08oteldemo\"0\n\x08\x43\x61rtItem\x12\x12\n\nproduct_id\x18\x01 \x01(\t\x12\x10\n\x08quantity\x18\x02 \x01(\x05\"C\n\x0e\x41\x64\x64ItemRequest\x12\x0f\n\x07user_id\x18\x01 \x01(\t\x12 \n\x04item\x18\x02 \x01(\x0b\x32\x12.oteldemo.CartItem\"#\n\x10\x45mptyCartRequest\x12\x0f\n\x07user_id\x18\x01 \x01(\t\"!\n\x0eGetCartRequest\x12\x0f\n\x07user_id\x18\x01 \x01(\t\":\n\x04\x43\x61rt\x12\x0f\n\x07user_id\x18\x01 \x01(\t\x12!\n\x05items\x18\x02 \x03(\x0b\x32\x12.oteldemo.CartItem\"\x07\n\x05\x45mpty\"B\n\x1aListRecommendationsRequest\x12\x0f\n\x07user_id\x18\x01 \x01(\t\x12\x13\n\x0bproduct_ids\x18\x02 \x03(\t\"2\n\x1bListRecommendationsResponse\x12\x13\n\x0bproduct_ids\x18\x01 \x03(\t\"\x81\x01\n\x07Product\x12\n\n\x02id\x18\x01 \x01(\t\x12\x0c\n\x04name\x18\x02 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x03 \x01(\t\x12\x0f\n\x07picture\x18\x04 \x01(\t\x12\"\n\tprice_usd\x18\x05 \x01(\x0b\x32\x0f.oteldemo.Money\x12\x12\n\ncategories\x18\x06 \x03(\t\";\n\x14ListProductsResponse\x12#\n\x08products\x18\x01 \x03(\x0b\x32\x11.oteldemo.Product\"\x1f\n\x11GetProductRequest\x12\n\n\x02id\x18\x01 \x01(\t\"&\n\x15SearchProductsRequest\x12\r\n\x05query\x18\x01 \x01(\t\"<\n\x16SearchProductsResponse\x12\"\n\x07results\x18\x01 \x03(\x0b\x32\x11.oteldemo.Product\"X\n\x0fGetQuoteRequest\x12\"\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0b\x32\x11.oteldemo.Address\x12!\n\x05items\x18\x02 \x03(\x0b\x32\x12.oteldemo.CartItem\"5\n\x10GetQuoteResponse\x12!\n\x08\x63ost_usd\x18\x01 \x01(\x0b\x32\x0f.oteldemo.Money\"Y\n\x10ShipOrderRequest\x12\"\n\x07\x61\x64\x64ress\x18\x01 \x01(\x0b\x32\x11.oteldemo.Address\x12!\n\x05items\x18\x02 \x03(\x0b\x32\x12.oteldemo.CartItem\"(\n\x11ShipOrderResponse\x12\x13\n\x0btracking_id\x18\x01 \x01(\t\"a\n\x07\x41\x64\x64ress\x12\x16\n\x0estreet_address\x18\x01 \x01(\t\x12\x0c\n\x04\x63ity\x18\x02 \x01(\t\x12\r\n\x05state\x18\x03 \x01(\t\x12\x0f\n\x07\x63ountry\x18\x04 \x01(\t\x12\x10\n\x08zip_code\x18\x05 \x01(\t\"<\n\x05Money\x12\x15\n\rcurrency_code\x18\x01 \x01(\t\x12\r\n\x05units\x18\x02 \x01(\x03\x12\r\n\x05nanos\x18\x03 \x01(\x05\"8\n\x1eGetSupportedCurrenciesResponse\x12\x16\n\x0e\x63urrency_codes\x18\x01 \x03(\t\"K\n\x19\x43urrencyConversionRequest\x12\x1d\n\x04\x66rom\x18\x01 \x01(\x0b\x32\x0f.oteldemo.Money\x12\x0f\n\x07to_code\x18\x02 \x01(\t\"\x90\x01\n\x0e\x43reditCardInfo\x12\x1a\n\x12\x63redit_card_number\x18\x01 \x01(\t\x12\x17\n\x0f\x63redit_card_cvv\x18\x02 \x01(\x05\x12#\n\x1b\x63redit_card_expiration_year\x18\x03 \x01(\x05\x12$\n\x1c\x63redit_card_expiration_month\x18\x04 \x01(\x05\"_\n\rChargeRequest\x12\x1f\n\x06\x61mount\x18\x01 \x01(\x0b\x32\x0f.oteldemo.Money\x12-\n\x0b\x63redit_card\x18\x02 \x01(\x0b\x32\x18.oteldemo.CreditCardInfo\"(\n\x0e\x43hargeResponse\x12\x16\n\x0etransaction_id\x18\x01 \x01(\t\"L\n\tOrderItem\x12 \n\x04item\x18\x01 \x01(\x0b\x32\x12.oteldemo.CartItem\x12\x1d\n\x04\x63ost\x18\x02 \x01(\x0b\x32\x0f.oteldemo.Money\"\xb6\x01\n\x0bOrderResult\x12\x10\n\x08order_id\x18\x01 \x01(\t\x12\x1c\n\x14shipping_tracking_id\x18\x02 \x01(\t\x12&\n\rshipping_cost\x18\x03 \x01(\x0b\x32\x0f.oteldemo.Money\x12+\n\x10shipping_address\x18\x04 \x01(\x0b\x32\x11.oteldemo.Address\x12\"\n\x05items\x18\x05 \x03(\x0b\x32\x13.oteldemo.OrderItem\"S\n\x1cSendOrderConfirmationRequest\x12\r\n\x05\x65mail\x18\x01 \x01(\t\x12$\n\x05order\x18\x02 \x01(\x0b\x32\x15.oteldemo.OrderResult\"\x9d\x01\n\x11PlaceOrderRequest\x12\x0f\n\x07user_id\x18\x01 \x01(\t\x12\x15\n\ruser_currency\x18\x02 \x01(\t\x12\"\n\x07\x61\x64\x64ress\x18\x03 \x01(\x0b\x32\x11.oteldemo.Address\x12\r\n\x05\x65mail\x18\x05 \x01(\t\x12-\n\x0b\x63redit_card\x18\x06 \x01(\x0b\x32\x18.oteldemo.CreditCardInfo\":\n\x12PlaceOrderResponse\x12$\n\x05order\x18\x01 \x01(\x0b\x32\x15.oteldemo.OrderResult\"!\n\tAdRequest\x12\x14\n\x0c\x63ontext_keys\x18\x01 \x03(\t\"\'\n\nAdResponse\x12\x19\n\x03\x61\x64s\x18\x01 \x03(\x0b\x32\x0c.oteldemo.Ad\"(\n\x02\x41\x64\x12\x14\n\x0credirect_url\x18\x01 \x01(\t\x12\x0c\n\x04text\x18\x02 \x01(\t\":\n\x04\x46lag\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x0f\n\x07\x65nabled\x18\x03 \x01(\x08\"\x1e\n\x0eGetFlagRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"/\n\x0fGetFlagResponse\x12\x1c\n\x04\x66lag\x18\x01 \x01(\x0b\x32\x0e.oteldemo.Flag\"G\n\x11\x43reateFlagRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x13\n\x0b\x64\x65scription\x18\x02 \x01(\t\x12\x0f\n\x07\x65nabled\x18\x03 \x01(\x08\"2\n\x12\x43reateFlagResponse\x12\x1c\n\x04\x66lag\x18\x01 \x01(\x0b\x32\x0e.oteldemo.Flag\"2\n\x11UpdateFlagRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\x12\x0f\n\x07\x65nabled\x18\x02 \x01(\x08\"\x14\n\x12UpdateFlagResponse\"\x12\n\x10ListFlagsRequest\"1\n\x11ListFlagsResponse\x12\x1c\n\x04\x66lag\x18\x01 \x03(\x0b\x32\x0e.oteldemo.Flag\"!\n\x11\x44\x65leteFlagRequest\x12\x0c\n\x04name\x18\x01 \x01(\t\"\x14\n\x12\x44\x65leteFlagResponse2\xb8\x01\n\x0b\x43\x61rtService\x12\x36\n\x07\x41\x64\x64Item\x12\x18.oteldemo.AddItemRequest\x1a\x0f.oteldemo.Empty\"\x00\x12\x35\n\x07GetCart\x12\x18.oteldemo.GetCartRequest\x1a\x0e.oteldemo.Cart\"\x00\x12:\n\tEmptyCart\x12\x1a.oteldemo.EmptyCartRequest\x1a\x0f.oteldemo.Empty\"\x00\x32}\n\x15RecommendationService\x12\x64\n\x13ListRecommendations\x12$.oteldemo.ListRecommendationsRequest\x1a%.oteldemo.ListRecommendationsResponse\"\x00\x32\xf1\x01\n\x15ProductCatalogService\x12\x41\n\x0cListProducts\x12\x0f.oteldemo.Empty\x1a\x1e.oteldemo.ListProductsResponse\"\x00\x12>\n\nGetProduct\x12\x1b.oteldemo.GetProductRequest\x1a\x11.oteldemo.Product\"\x00\x12U\n\x0eSearchProducts\x12\x1f.oteldemo.SearchProductsRequest\x1a .oteldemo.SearchProductsResponse\"\x00\x32\x9e\x01\n\x0fShippingService\x12\x43\n\x08GetQuote\x12\x19.oteldemo.GetQuoteRequest\x1a\x1a.oteldemo.GetQuoteResponse\"\x00\x12\x46\n\tShipOrder\x12\x1a.oteldemo.ShipOrderRequest\x1a\x1b.oteldemo.ShipOrderResponse\"\x00\x32\xab\x01\n\x0f\x43urrencyService\x12U\n\x16GetSupportedCurrencies\x12\x0f.oteldemo.Empty\x1a(.oteldemo.GetSupportedCurrenciesResponse\"\x00\x12\x41\n\x07\x43onvert\x12#.oteldemo.CurrencyConversionRequest\x1a\x0f.oteldemo.Money\"\x00\x32O\n\x0ePaymentService\x12=\n\x06\x43harge\x12\x17.oteldemo.ChargeRequest\x1a\x18.oteldemo.ChargeResponse\"\x00\x32\x62\n\x0c\x45mailService\x12R\n\x15SendOrderConfirmation\x12&.oteldemo.SendOrderConfirmationRequest\x1a\x0f.oteldemo.Empty\"\x00\x32\\\n\x0f\x43heckoutService\x12I\n\nPlaceOrder\x12\x1b.oteldemo.PlaceOrderRequest\x1a\x1c.oteldemo.PlaceOrderResponse\"\x00\x32\x42\n\tAdService\x12\x35\n\x06GetAds\x12\x13.oteldemo.AdRequest\x1a\x14.oteldemo.AdResponse\"\x00\x32\xff\x02\n\x12\x46\x65\x61tureFlagService\x12@\n\x07GetFlag\x12\x18.oteldemo.GetFlagRequest\x1a\x19.oteldemo.GetFlagResponse\"\x00\x12I\n\nCreateFlag\x12\x1b.oteldemo.CreateFlagRequest\x1a\x1c.oteldemo.CreateFlagResponse\"\x00\x12I\n\nUpdateFlag\x12\x1b.oteldemo.UpdateFlagRequest\x1a\x1c.oteldemo.UpdateFlagResponse\"\x00\x12\x46\n\tListFlags\x12\x1a.oteldemo.ListFlagsRequest\x1a\x1b.oteldemo.ListFlagsResponse\"\x00\x12I\n\nDeleteFlag\x12\x1b.oteldemo.DeleteFlagRequest\x1a\x1c.oteldemo.DeleteFlagResponse\"\x00\x42\x13Z\x11genproto/oteldemob\x06proto3')
+
+_globals = globals()
+_builder.BuildMessageAndEnumDescriptors(DESCRIPTOR, _globals)
+_builder.BuildTopDescriptorsAndMessages(DESCRIPTOR, 'demo_pb2', _globals)
+if _descriptor._USE_C_DESCRIPTORS == False:
+ DESCRIPTOR._options = None
+ DESCRIPTOR._serialized_options = b'Z\021genproto/oteldemo'
+ _globals['_CARTITEM']._serialized_start=24
+ _globals['_CARTITEM']._serialized_end=72
+ _globals['_ADDITEMREQUEST']._serialized_start=74
+ _globals['_ADDITEMREQUEST']._serialized_end=141
+ _globals['_EMPTYCARTREQUEST']._serialized_start=143
+ _globals['_EMPTYCARTREQUEST']._serialized_end=178
+ _globals['_GETCARTREQUEST']._serialized_start=180
+ _globals['_GETCARTREQUEST']._serialized_end=213
+ _globals['_CART']._serialized_start=215
+ _globals['_CART']._serialized_end=273
+ _globals['_EMPTY']._serialized_start=275
+ _globals['_EMPTY']._serialized_end=282
+ _globals['_LISTRECOMMENDATIONSREQUEST']._serialized_start=284
+ _globals['_LISTRECOMMENDATIONSREQUEST']._serialized_end=350
+ _globals['_LISTRECOMMENDATIONSRESPONSE']._serialized_start=352
+ _globals['_LISTRECOMMENDATIONSRESPONSE']._serialized_end=402
+ _globals['_PRODUCT']._serialized_start=405
+ _globals['_PRODUCT']._serialized_end=534
+ _globals['_LISTPRODUCTSRESPONSE']._serialized_start=536
+ _globals['_LISTPRODUCTSRESPONSE']._serialized_end=595
+ _globals['_GETPRODUCTREQUEST']._serialized_start=597
+ _globals['_GETPRODUCTREQUEST']._serialized_end=628
+ _globals['_SEARCHPRODUCTSREQUEST']._serialized_start=630
+ _globals['_SEARCHPRODUCTSREQUEST']._serialized_end=668
+ _globals['_SEARCHPRODUCTSRESPONSE']._serialized_start=670
+ _globals['_SEARCHPRODUCTSRESPONSE']._serialized_end=730
+ _globals['_GETQUOTEREQUEST']._serialized_start=732
+ _globals['_GETQUOTEREQUEST']._serialized_end=820
+ _globals['_GETQUOTERESPONSE']._serialized_start=822
+ _globals['_GETQUOTERESPONSE']._serialized_end=875
+ _globals['_SHIPORDERREQUEST']._serialized_start=877
+ _globals['_SHIPORDERREQUEST']._serialized_end=966
+ _globals['_SHIPORDERRESPONSE']._serialized_start=968
+ _globals['_SHIPORDERRESPONSE']._serialized_end=1008
+ _globals['_ADDRESS']._serialized_start=1010
+ _globals['_ADDRESS']._serialized_end=1107
+ _globals['_MONEY']._serialized_start=1109
+ _globals['_MONEY']._serialized_end=1169
+ _globals['_GETSUPPORTEDCURRENCIESRESPONSE']._serialized_start=1171
+ _globals['_GETSUPPORTEDCURRENCIESRESPONSE']._serialized_end=1227
+ _globals['_CURRENCYCONVERSIONREQUEST']._serialized_start=1229
+ _globals['_CURRENCYCONVERSIONREQUEST']._serialized_end=1304
+ _globals['_CREDITCARDINFO']._serialized_start=1307
+ _globals['_CREDITCARDINFO']._serialized_end=1451
+ _globals['_CHARGEREQUEST']._serialized_start=1453
+ _globals['_CHARGEREQUEST']._serialized_end=1548
+ _globals['_CHARGERESPONSE']._serialized_start=1550
+ _globals['_CHARGERESPONSE']._serialized_end=1590
+ _globals['_ORDERITEM']._serialized_start=1592
+ _globals['_ORDERITEM']._serialized_end=1668
+ _globals['_ORDERRESULT']._serialized_start=1671
+ _globals['_ORDERRESULT']._serialized_end=1853
+ _globals['_SENDORDERCONFIRMATIONREQUEST']._serialized_start=1855
+ _globals['_SENDORDERCONFIRMATIONREQUEST']._serialized_end=1938
+ _globals['_PLACEORDERREQUEST']._serialized_start=1941
+ _globals['_PLACEORDERREQUEST']._serialized_end=2098
+ _globals['_PLACEORDERRESPONSE']._serialized_start=2100
+ _globals['_PLACEORDERRESPONSE']._serialized_end=2158
+ _globals['_ADREQUEST']._serialized_start=2160
+ _globals['_ADREQUEST']._serialized_end=2193
+ _globals['_ADRESPONSE']._serialized_start=2195
+ _globals['_ADRESPONSE']._serialized_end=2234
+ _globals['_AD']._serialized_start=2236
+ _globals['_AD']._serialized_end=2276
+ _globals['_FLAG']._serialized_start=2278
+ _globals['_FLAG']._serialized_end=2336
+ _globals['_GETFLAGREQUEST']._serialized_start=2338
+ _globals['_GETFLAGREQUEST']._serialized_end=2368
+ _globals['_GETFLAGRESPONSE']._serialized_start=2370
+ _globals['_GETFLAGRESPONSE']._serialized_end=2417
+ _globals['_CREATEFLAGREQUEST']._serialized_start=2419
+ _globals['_CREATEFLAGREQUEST']._serialized_end=2490
+ _globals['_CREATEFLAGRESPONSE']._serialized_start=2492
+ _globals['_CREATEFLAGRESPONSE']._serialized_end=2542
+ _globals['_UPDATEFLAGREQUEST']._serialized_start=2544
+ _globals['_UPDATEFLAGREQUEST']._serialized_end=2594
+ _globals['_UPDATEFLAGRESPONSE']._serialized_start=2596
+ _globals['_UPDATEFLAGRESPONSE']._serialized_end=2616
+ _globals['_LISTFLAGSREQUEST']._serialized_start=2618
+ _globals['_LISTFLAGSREQUEST']._serialized_end=2636
+ _globals['_LISTFLAGSRESPONSE']._serialized_start=2638
+ _globals['_LISTFLAGSRESPONSE']._serialized_end=2687
+ _globals['_DELETEFLAGREQUEST']._serialized_start=2689
+ _globals['_DELETEFLAGREQUEST']._serialized_end=2722
+ _globals['_DELETEFLAGRESPONSE']._serialized_start=2724
+ _globals['_DELETEFLAGRESPONSE']._serialized_end=2744
+ _globals['_CARTSERVICE']._serialized_start=2747
+ _globals['_CARTSERVICE']._serialized_end=2931
+ _globals['_RECOMMENDATIONSERVICE']._serialized_start=2933
+ _globals['_RECOMMENDATIONSERVICE']._serialized_end=3058
+ _globals['_PRODUCTCATALOGSERVICE']._serialized_start=3061
+ _globals['_PRODUCTCATALOGSERVICE']._serialized_end=3302
+ _globals['_SHIPPINGSERVICE']._serialized_start=3305
+ _globals['_SHIPPINGSERVICE']._serialized_end=3463
+ _globals['_CURRENCYSERVICE']._serialized_start=3466
+ _globals['_CURRENCYSERVICE']._serialized_end=3637
+ _globals['_PAYMENTSERVICE']._serialized_start=3639
+ _globals['_PAYMENTSERVICE']._serialized_end=3718
+ _globals['_EMAILSERVICE']._serialized_start=3720
+ _globals['_EMAILSERVICE']._serialized_end=3818
+ _globals['_CHECKOUTSERVICE']._serialized_start=3820
+ _globals['_CHECKOUTSERVICE']._serialized_end=3912
+ _globals['_ADSERVICE']._serialized_start=3914
+ _globals['_ADSERVICE']._serialized_end=3980
+ _globals['_FEATUREFLAGSERVICE']._serialized_start=3983
+ _globals['_FEATUREFLAGSERVICE']._serialized_end=4366
+# @@protoc_insertion_point(module_scope)
diff --git a/src/recommendation/demo_pb2_grpc.py b/src/recommendation/demo_pb2_grpc.py
new file mode 100644
index 0000000..cb7c9e7
--- /dev/null
+++ b/src/recommendation/demo_pb2_grpc.py
@@ -0,0 +1,1005 @@
+# Generated by the gRPC Python protocol compiler plugin. DO NOT EDIT!
+"""Client and server classes corresponding to protobuf-defined services."""
+import grpc
+
+import demo_pb2 as demo__pb2
+
+
+class CartServiceStub(object):
+ """-----------------Cart service-----------------
+
+ """
+
+ def __init__(self, channel):
+ """Constructor.
+
+ Args:
+ channel: A grpc.Channel.
+ """
+ self.AddItem = channel.unary_unary(
+ '/oteldemo.CartService/AddItem',
+ request_serializer=demo__pb2.AddItemRequest.SerializeToString,
+ response_deserializer=demo__pb2.Empty.FromString,
+ )
+ self.GetCart = channel.unary_unary(
+ '/oteldemo.CartService/GetCart',
+ request_serializer=demo__pb2.GetCartRequest.SerializeToString,
+ response_deserializer=demo__pb2.Cart.FromString,
+ )
+ self.EmptyCart = channel.unary_unary(
+ '/oteldemo.CartService/EmptyCart',
+ request_serializer=demo__pb2.EmptyCartRequest.SerializeToString,
+ response_deserializer=demo__pb2.Empty.FromString,
+ )
+
+
+class CartServiceServicer(object):
+ """-----------------Cart service-----------------
+
+ """
+
+ def AddItem(self, request, context):
+ """Missing associated documentation comment in .proto file."""
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+ def GetCart(self, request, context):
+ """Missing associated documentation comment in .proto file."""
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+ def EmptyCart(self, request, context):
+ """Missing associated documentation comment in .proto file."""
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+
+def add_CartServiceServicer_to_server(servicer, server):
+ rpc_method_handlers = {
+ 'AddItem': grpc.unary_unary_rpc_method_handler(
+ servicer.AddItem,
+ request_deserializer=demo__pb2.AddItemRequest.FromString,
+ response_serializer=demo__pb2.Empty.SerializeToString,
+ ),
+ 'GetCart': grpc.unary_unary_rpc_method_handler(
+ servicer.GetCart,
+ request_deserializer=demo__pb2.GetCartRequest.FromString,
+ response_serializer=demo__pb2.Cart.SerializeToString,
+ ),
+ 'EmptyCart': grpc.unary_unary_rpc_method_handler(
+ servicer.EmptyCart,
+ request_deserializer=demo__pb2.EmptyCartRequest.FromString,
+ response_serializer=demo__pb2.Empty.SerializeToString,
+ ),
+ }
+ generic_handler = grpc.method_handlers_generic_handler(
+ 'oteldemo.CartService', rpc_method_handlers)
+ server.add_generic_rpc_handlers((generic_handler,))
+
+
+ # This class is part of an EXPERIMENTAL API.
+class CartService(object):
+ """-----------------Cart service-----------------
+
+ """
+
+ @staticmethod
+ def AddItem(request,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.unary_unary(request, target, '/oteldemo.CartService/AddItem',
+ demo__pb2.AddItemRequest.SerializeToString,
+ demo__pb2.Empty.FromString,
+ options, channel_credentials,
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+ @staticmethod
+ def GetCart(request,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.unary_unary(request, target, '/oteldemo.CartService/GetCart',
+ demo__pb2.GetCartRequest.SerializeToString,
+ demo__pb2.Cart.FromString,
+ options, channel_credentials,
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+ @staticmethod
+ def EmptyCart(request,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.unary_unary(request, target, '/oteldemo.CartService/EmptyCart',
+ demo__pb2.EmptyCartRequest.SerializeToString,
+ demo__pb2.Empty.FromString,
+ options, channel_credentials,
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+
+class RecommendationServiceStub(object):
+ """---------------Recommendation service----------
+
+ """
+
+ def __init__(self, channel):
+ """Constructor.
+
+ Args:
+ channel: A grpc.Channel.
+ """
+ self.ListRecommendations = channel.unary_unary(
+ '/oteldemo.RecommendationService/ListRecommendations',
+ request_serializer=demo__pb2.ListRecommendationsRequest.SerializeToString,
+ response_deserializer=demo__pb2.ListRecommendationsResponse.FromString,
+ )
+
+
+class RecommendationServiceServicer(object):
+ """---------------Recommendation service----------
+
+ """
+
+ def ListRecommendations(self, request, context):
+ """Missing associated documentation comment in .proto file."""
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+
+def add_RecommendationServiceServicer_to_server(servicer, server):
+ rpc_method_handlers = {
+ 'ListRecommendations': grpc.unary_unary_rpc_method_handler(
+ servicer.ListRecommendations,
+ request_deserializer=demo__pb2.ListRecommendationsRequest.FromString,
+ response_serializer=demo__pb2.ListRecommendationsResponse.SerializeToString,
+ ),
+ }
+ generic_handler = grpc.method_handlers_generic_handler(
+ 'oteldemo.RecommendationService', rpc_method_handlers)
+ server.add_generic_rpc_handlers((generic_handler,))
+
+
+ # This class is part of an EXPERIMENTAL API.
+class RecommendationService(object):
+ """---------------Recommendation service----------
+
+ """
+
+ @staticmethod
+ def ListRecommendations(request,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.unary_unary(request, target, '/oteldemo.RecommendationService/ListRecommendations',
+ demo__pb2.ListRecommendationsRequest.SerializeToString,
+ demo__pb2.ListRecommendationsResponse.FromString,
+ options, channel_credentials,
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+
+class ProductCatalogServiceStub(object):
+ """---------------Product Catalog----------------
+
+ """
+
+ def __init__(self, channel):
+ """Constructor.
+
+ Args:
+ channel: A grpc.Channel.
+ """
+ self.ListProducts = channel.unary_unary(
+ '/oteldemo.ProductCatalogService/ListProducts',
+ request_serializer=demo__pb2.Empty.SerializeToString,
+ response_deserializer=demo__pb2.ListProductsResponse.FromString,
+ )
+ self.GetProduct = channel.unary_unary(
+ '/oteldemo.ProductCatalogService/GetProduct',
+ request_serializer=demo__pb2.GetProductRequest.SerializeToString,
+ response_deserializer=demo__pb2.Product.FromString,
+ )
+ self.SearchProducts = channel.unary_unary(
+ '/oteldemo.ProductCatalogService/SearchProducts',
+ request_serializer=demo__pb2.SearchProductsRequest.SerializeToString,
+ response_deserializer=demo__pb2.SearchProductsResponse.FromString,
+ )
+
+
+class ProductCatalogServiceServicer(object):
+ """---------------Product Catalog----------------
+
+ """
+
+ def ListProducts(self, request, context):
+ """Missing associated documentation comment in .proto file."""
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+ def GetProduct(self, request, context):
+ """Missing associated documentation comment in .proto file."""
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+ def SearchProducts(self, request, context):
+ """Missing associated documentation comment in .proto file."""
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+
+def add_ProductCatalogServiceServicer_to_server(servicer, server):
+ rpc_method_handlers = {
+ 'ListProducts': grpc.unary_unary_rpc_method_handler(
+ servicer.ListProducts,
+ request_deserializer=demo__pb2.Empty.FromString,
+ response_serializer=demo__pb2.ListProductsResponse.SerializeToString,
+ ),
+ 'GetProduct': grpc.unary_unary_rpc_method_handler(
+ servicer.GetProduct,
+ request_deserializer=demo__pb2.GetProductRequest.FromString,
+ response_serializer=demo__pb2.Product.SerializeToString,
+ ),
+ 'SearchProducts': grpc.unary_unary_rpc_method_handler(
+ servicer.SearchProducts,
+ request_deserializer=demo__pb2.SearchProductsRequest.FromString,
+ response_serializer=demo__pb2.SearchProductsResponse.SerializeToString,
+ ),
+ }
+ generic_handler = grpc.method_handlers_generic_handler(
+ 'oteldemo.ProductCatalogService', rpc_method_handlers)
+ server.add_generic_rpc_handlers((generic_handler,))
+
+
+ # This class is part of an EXPERIMENTAL API.
+class ProductCatalogService(object):
+ """---------------Product Catalog----------------
+
+ """
+
+ @staticmethod
+ def ListProducts(request,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.unary_unary(request, target, '/oteldemo.ProductCatalogService/ListProducts',
+ demo__pb2.Empty.SerializeToString,
+ demo__pb2.ListProductsResponse.FromString,
+ options, channel_credentials,
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+ @staticmethod
+ def GetProduct(request,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.unary_unary(request, target, '/oteldemo.ProductCatalogService/GetProduct',
+ demo__pb2.GetProductRequest.SerializeToString,
+ demo__pb2.Product.FromString,
+ options, channel_credentials,
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+ @staticmethod
+ def SearchProducts(request,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.unary_unary(request, target, '/oteldemo.ProductCatalogService/SearchProducts',
+ demo__pb2.SearchProductsRequest.SerializeToString,
+ demo__pb2.SearchProductsResponse.FromString,
+ options, channel_credentials,
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+
+class ShippingServiceStub(object):
+ """---------------Shipping Service----------
+
+ """
+
+ def __init__(self, channel):
+ """Constructor.
+
+ Args:
+ channel: A grpc.Channel.
+ """
+ self.GetQuote = channel.unary_unary(
+ '/oteldemo.ShippingService/GetQuote',
+ request_serializer=demo__pb2.GetQuoteRequest.SerializeToString,
+ response_deserializer=demo__pb2.GetQuoteResponse.FromString,
+ )
+ self.ShipOrder = channel.unary_unary(
+ '/oteldemo.ShippingService/ShipOrder',
+ request_serializer=demo__pb2.ShipOrderRequest.SerializeToString,
+ response_deserializer=demo__pb2.ShipOrderResponse.FromString,
+ )
+
+
+class ShippingServiceServicer(object):
+ """---------------Shipping Service----------
+
+ """
+
+ def GetQuote(self, request, context):
+ """Missing associated documentation comment in .proto file."""
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+ def ShipOrder(self, request, context):
+ """Missing associated documentation comment in .proto file."""
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+
+def add_ShippingServiceServicer_to_server(servicer, server):
+ rpc_method_handlers = {
+ 'GetQuote': grpc.unary_unary_rpc_method_handler(
+ servicer.GetQuote,
+ request_deserializer=demo__pb2.GetQuoteRequest.FromString,
+ response_serializer=demo__pb2.GetQuoteResponse.SerializeToString,
+ ),
+ 'ShipOrder': grpc.unary_unary_rpc_method_handler(
+ servicer.ShipOrder,
+ request_deserializer=demo__pb2.ShipOrderRequest.FromString,
+ response_serializer=demo__pb2.ShipOrderResponse.SerializeToString,
+ ),
+ }
+ generic_handler = grpc.method_handlers_generic_handler(
+ 'oteldemo.ShippingService', rpc_method_handlers)
+ server.add_generic_rpc_handlers((generic_handler,))
+
+
+ # This class is part of an EXPERIMENTAL API.
+class ShippingService(object):
+ """---------------Shipping Service----------
+
+ """
+
+ @staticmethod
+ def GetQuote(request,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.unary_unary(request, target, '/oteldemo.ShippingService/GetQuote',
+ demo__pb2.GetQuoteRequest.SerializeToString,
+ demo__pb2.GetQuoteResponse.FromString,
+ options, channel_credentials,
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+ @staticmethod
+ def ShipOrder(request,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.unary_unary(request, target, '/oteldemo.ShippingService/ShipOrder',
+ demo__pb2.ShipOrderRequest.SerializeToString,
+ demo__pb2.ShipOrderResponse.FromString,
+ options, channel_credentials,
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+
+class CurrencyServiceStub(object):
+ """-----------------Currency service-----------------
+
+ """
+
+ def __init__(self, channel):
+ """Constructor.
+
+ Args:
+ channel: A grpc.Channel.
+ """
+ self.GetSupportedCurrencies = channel.unary_unary(
+ '/oteldemo.CurrencyService/GetSupportedCurrencies',
+ request_serializer=demo__pb2.Empty.SerializeToString,
+ response_deserializer=demo__pb2.GetSupportedCurrenciesResponse.FromString,
+ )
+ self.Convert = channel.unary_unary(
+ '/oteldemo.CurrencyService/Convert',
+ request_serializer=demo__pb2.CurrencyConversionRequest.SerializeToString,
+ response_deserializer=demo__pb2.Money.FromString,
+ )
+
+
+class CurrencyServiceServicer(object):
+ """-----------------Currency service-----------------
+
+ """
+
+ def GetSupportedCurrencies(self, request, context):
+ """Missing associated documentation comment in .proto file."""
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+ def Convert(self, request, context):
+ """Missing associated documentation comment in .proto file."""
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+
+def add_CurrencyServiceServicer_to_server(servicer, server):
+ rpc_method_handlers = {
+ 'GetSupportedCurrencies': grpc.unary_unary_rpc_method_handler(
+ servicer.GetSupportedCurrencies,
+ request_deserializer=demo__pb2.Empty.FromString,
+ response_serializer=demo__pb2.GetSupportedCurrenciesResponse.SerializeToString,
+ ),
+ 'Convert': grpc.unary_unary_rpc_method_handler(
+ servicer.Convert,
+ request_deserializer=demo__pb2.CurrencyConversionRequest.FromString,
+ response_serializer=demo__pb2.Money.SerializeToString,
+ ),
+ }
+ generic_handler = grpc.method_handlers_generic_handler(
+ 'oteldemo.CurrencyService', rpc_method_handlers)
+ server.add_generic_rpc_handlers((generic_handler,))
+
+
+ # This class is part of an EXPERIMENTAL API.
+class CurrencyService(object):
+ """-----------------Currency service-----------------
+
+ """
+
+ @staticmethod
+ def GetSupportedCurrencies(request,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.unary_unary(request, target, '/oteldemo.CurrencyService/GetSupportedCurrencies',
+ demo__pb2.Empty.SerializeToString,
+ demo__pb2.GetSupportedCurrenciesResponse.FromString,
+ options, channel_credentials,
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+ @staticmethod
+ def Convert(request,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.unary_unary(request, target, '/oteldemo.CurrencyService/Convert',
+ demo__pb2.CurrencyConversionRequest.SerializeToString,
+ demo__pb2.Money.FromString,
+ options, channel_credentials,
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+
+class PaymentServiceStub(object):
+ """-------------Payment service-----------------
+
+ """
+
+ def __init__(self, channel):
+ """Constructor.
+
+ Args:
+ channel: A grpc.Channel.
+ """
+ self.Charge = channel.unary_unary(
+ '/oteldemo.PaymentService/Charge',
+ request_serializer=demo__pb2.ChargeRequest.SerializeToString,
+ response_deserializer=demo__pb2.ChargeResponse.FromString,
+ )
+
+
+class PaymentServiceServicer(object):
+ """-------------Payment service-----------------
+
+ """
+
+ def Charge(self, request, context):
+ """Missing associated documentation comment in .proto file."""
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+
+def add_PaymentServiceServicer_to_server(servicer, server):
+ rpc_method_handlers = {
+ 'Charge': grpc.unary_unary_rpc_method_handler(
+ servicer.Charge,
+ request_deserializer=demo__pb2.ChargeRequest.FromString,
+ response_serializer=demo__pb2.ChargeResponse.SerializeToString,
+ ),
+ }
+ generic_handler = grpc.method_handlers_generic_handler(
+ 'oteldemo.PaymentService', rpc_method_handlers)
+ server.add_generic_rpc_handlers((generic_handler,))
+
+
+ # This class is part of an EXPERIMENTAL API.
+class PaymentService(object):
+ """-------------Payment service-----------------
+
+ """
+
+ @staticmethod
+ def Charge(request,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.unary_unary(request, target, '/oteldemo.PaymentService/Charge',
+ demo__pb2.ChargeRequest.SerializeToString,
+ demo__pb2.ChargeResponse.FromString,
+ options, channel_credentials,
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+
+class EmailServiceStub(object):
+ """-------------Email service-----------------
+
+ """
+
+ def __init__(self, channel):
+ """Constructor.
+
+ Args:
+ channel: A grpc.Channel.
+ """
+ self.SendOrderConfirmation = channel.unary_unary(
+ '/oteldemo.EmailService/SendOrderConfirmation',
+ request_serializer=demo__pb2.SendOrderConfirmationRequest.SerializeToString,
+ response_deserializer=demo__pb2.Empty.FromString,
+ )
+
+
+class EmailServiceServicer(object):
+ """-------------Email service-----------------
+
+ """
+
+ def SendOrderConfirmation(self, request, context):
+ """Missing associated documentation comment in .proto file."""
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+
+def add_EmailServiceServicer_to_server(servicer, server):
+ rpc_method_handlers = {
+ 'SendOrderConfirmation': grpc.unary_unary_rpc_method_handler(
+ servicer.SendOrderConfirmation,
+ request_deserializer=demo__pb2.SendOrderConfirmationRequest.FromString,
+ response_serializer=demo__pb2.Empty.SerializeToString,
+ ),
+ }
+ generic_handler = grpc.method_handlers_generic_handler(
+ 'oteldemo.EmailService', rpc_method_handlers)
+ server.add_generic_rpc_handlers((generic_handler,))
+
+
+ # This class is part of an EXPERIMENTAL API.
+class EmailService(object):
+ """-------------Email service-----------------
+
+ """
+
+ @staticmethod
+ def SendOrderConfirmation(request,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.unary_unary(request, target, '/oteldemo.EmailService/SendOrderConfirmation',
+ demo__pb2.SendOrderConfirmationRequest.SerializeToString,
+ demo__pb2.Empty.FromString,
+ options, channel_credentials,
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+
+class CheckoutServiceStub(object):
+ """-------------Checkout service-----------------
+
+ """
+
+ def __init__(self, channel):
+ """Constructor.
+
+ Args:
+ channel: A grpc.Channel.
+ """
+ self.PlaceOrder = channel.unary_unary(
+ '/oteldemo.CheckoutService/PlaceOrder',
+ request_serializer=demo__pb2.PlaceOrderRequest.SerializeToString,
+ response_deserializer=demo__pb2.PlaceOrderResponse.FromString,
+ )
+
+
+class CheckoutServiceServicer(object):
+ """-------------Checkout service-----------------
+
+ """
+
+ def PlaceOrder(self, request, context):
+ """Missing associated documentation comment in .proto file."""
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+
+def add_CheckoutServiceServicer_to_server(servicer, server):
+ rpc_method_handlers = {
+ 'PlaceOrder': grpc.unary_unary_rpc_method_handler(
+ servicer.PlaceOrder,
+ request_deserializer=demo__pb2.PlaceOrderRequest.FromString,
+ response_serializer=demo__pb2.PlaceOrderResponse.SerializeToString,
+ ),
+ }
+ generic_handler = grpc.method_handlers_generic_handler(
+ 'oteldemo.CheckoutService', rpc_method_handlers)
+ server.add_generic_rpc_handlers((generic_handler,))
+
+
+ # This class is part of an EXPERIMENTAL API.
+class CheckoutService(object):
+ """-------------Checkout service-----------------
+
+ """
+
+ @staticmethod
+ def PlaceOrder(request,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.unary_unary(request, target, '/oteldemo.CheckoutService/PlaceOrder',
+ demo__pb2.PlaceOrderRequest.SerializeToString,
+ demo__pb2.PlaceOrderResponse.FromString,
+ options, channel_credentials,
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+
+class AdServiceStub(object):
+ """------------Ad service------------------
+
+ """
+
+ def __init__(self, channel):
+ """Constructor.
+
+ Args:
+ channel: A grpc.Channel.
+ """
+ self.GetAds = channel.unary_unary(
+ '/oteldemo.AdService/GetAds',
+ request_serializer=demo__pb2.AdRequest.SerializeToString,
+ response_deserializer=demo__pb2.AdResponse.FromString,
+ )
+
+
+class AdServiceServicer(object):
+ """------------Ad service------------------
+
+ """
+
+ def GetAds(self, request, context):
+ """Missing associated documentation comment in .proto file."""
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+
+def add_AdServiceServicer_to_server(servicer, server):
+ rpc_method_handlers = {
+ 'GetAds': grpc.unary_unary_rpc_method_handler(
+ servicer.GetAds,
+ request_deserializer=demo__pb2.AdRequest.FromString,
+ response_serializer=demo__pb2.AdResponse.SerializeToString,
+ ),
+ }
+ generic_handler = grpc.method_handlers_generic_handler(
+ 'oteldemo.AdService', rpc_method_handlers)
+ server.add_generic_rpc_handlers((generic_handler,))
+
+
+ # This class is part of an EXPERIMENTAL API.
+class AdService(object):
+ """------------Ad service------------------
+
+ """
+
+ @staticmethod
+ def GetAds(request,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.unary_unary(request, target, '/oteldemo.AdService/GetAds',
+ demo__pb2.AdRequest.SerializeToString,
+ demo__pb2.AdResponse.FromString,
+ options, channel_credentials,
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+
+class FeatureFlagServiceStub(object):
+ """------------Feature flag service------------------
+
+ """
+
+ def __init__(self, channel):
+ """Constructor.
+
+ Args:
+ channel: A grpc.Channel.
+ """
+ self.GetFlag = channel.unary_unary(
+ '/oteldemo.FeatureFlagService/GetFlag',
+ request_serializer=demo__pb2.GetFlagRequest.SerializeToString,
+ response_deserializer=demo__pb2.GetFlagResponse.FromString,
+ )
+ self.CreateFlag = channel.unary_unary(
+ '/oteldemo.FeatureFlagService/CreateFlag',
+ request_serializer=demo__pb2.CreateFlagRequest.SerializeToString,
+ response_deserializer=demo__pb2.CreateFlagResponse.FromString,
+ )
+ self.UpdateFlag = channel.unary_unary(
+ '/oteldemo.FeatureFlagService/UpdateFlag',
+ request_serializer=demo__pb2.UpdateFlagRequest.SerializeToString,
+ response_deserializer=demo__pb2.UpdateFlagResponse.FromString,
+ )
+ self.ListFlags = channel.unary_unary(
+ '/oteldemo.FeatureFlagService/ListFlags',
+ request_serializer=demo__pb2.ListFlagsRequest.SerializeToString,
+ response_deserializer=demo__pb2.ListFlagsResponse.FromString,
+ )
+ self.DeleteFlag = channel.unary_unary(
+ '/oteldemo.FeatureFlagService/DeleteFlag',
+ request_serializer=demo__pb2.DeleteFlagRequest.SerializeToString,
+ response_deserializer=demo__pb2.DeleteFlagResponse.FromString,
+ )
+
+
+class FeatureFlagServiceServicer(object):
+ """------------Feature flag service------------------
+
+ """
+
+ def GetFlag(self, request, context):
+ """Missing associated documentation comment in .proto file."""
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+ def CreateFlag(self, request, context):
+ """Missing associated documentation comment in .proto file."""
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+ def UpdateFlag(self, request, context):
+ """Missing associated documentation comment in .proto file."""
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+ def ListFlags(self, request, context):
+ """Missing associated documentation comment in .proto file."""
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+ def DeleteFlag(self, request, context):
+ """Missing associated documentation comment in .proto file."""
+ context.set_code(grpc.StatusCode.UNIMPLEMENTED)
+ context.set_details('Method not implemented!')
+ raise NotImplementedError('Method not implemented!')
+
+
+def add_FeatureFlagServiceServicer_to_server(servicer, server):
+ rpc_method_handlers = {
+ 'GetFlag': grpc.unary_unary_rpc_method_handler(
+ servicer.GetFlag,
+ request_deserializer=demo__pb2.GetFlagRequest.FromString,
+ response_serializer=demo__pb2.GetFlagResponse.SerializeToString,
+ ),
+ 'CreateFlag': grpc.unary_unary_rpc_method_handler(
+ servicer.CreateFlag,
+ request_deserializer=demo__pb2.CreateFlagRequest.FromString,
+ response_serializer=demo__pb2.CreateFlagResponse.SerializeToString,
+ ),
+ 'UpdateFlag': grpc.unary_unary_rpc_method_handler(
+ servicer.UpdateFlag,
+ request_deserializer=demo__pb2.UpdateFlagRequest.FromString,
+ response_serializer=demo__pb2.UpdateFlagResponse.SerializeToString,
+ ),
+ 'ListFlags': grpc.unary_unary_rpc_method_handler(
+ servicer.ListFlags,
+ request_deserializer=demo__pb2.ListFlagsRequest.FromString,
+ response_serializer=demo__pb2.ListFlagsResponse.SerializeToString,
+ ),
+ 'DeleteFlag': grpc.unary_unary_rpc_method_handler(
+ servicer.DeleteFlag,
+ request_deserializer=demo__pb2.DeleteFlagRequest.FromString,
+ response_serializer=demo__pb2.DeleteFlagResponse.SerializeToString,
+ ),
+ }
+ generic_handler = grpc.method_handlers_generic_handler(
+ 'oteldemo.FeatureFlagService', rpc_method_handlers)
+ server.add_generic_rpc_handlers((generic_handler,))
+
+
+ # This class is part of an EXPERIMENTAL API.
+class FeatureFlagService(object):
+ """------------Feature flag service------------------
+
+ """
+
+ @staticmethod
+ def GetFlag(request,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.unary_unary(request, target, '/oteldemo.FeatureFlagService/GetFlag',
+ demo__pb2.GetFlagRequest.SerializeToString,
+ demo__pb2.GetFlagResponse.FromString,
+ options, channel_credentials,
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+ @staticmethod
+ def CreateFlag(request,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.unary_unary(request, target, '/oteldemo.FeatureFlagService/CreateFlag',
+ demo__pb2.CreateFlagRequest.SerializeToString,
+ demo__pb2.CreateFlagResponse.FromString,
+ options, channel_credentials,
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+ @staticmethod
+ def UpdateFlag(request,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.unary_unary(request, target, '/oteldemo.FeatureFlagService/UpdateFlag',
+ demo__pb2.UpdateFlagRequest.SerializeToString,
+ demo__pb2.UpdateFlagResponse.FromString,
+ options, channel_credentials,
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+ @staticmethod
+ def ListFlags(request,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.unary_unary(request, target, '/oteldemo.FeatureFlagService/ListFlags',
+ demo__pb2.ListFlagsRequest.SerializeToString,
+ demo__pb2.ListFlagsResponse.FromString,
+ options, channel_credentials,
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
+
+ @staticmethod
+ def DeleteFlag(request,
+ target,
+ options=(),
+ channel_credentials=None,
+ call_credentials=None,
+ insecure=False,
+ compression=None,
+ wait_for_ready=None,
+ timeout=None,
+ metadata=None):
+ return grpc.experimental.unary_unary(request, target, '/oteldemo.FeatureFlagService/DeleteFlag',
+ demo__pb2.DeleteFlagRequest.SerializeToString,
+ demo__pb2.DeleteFlagResponse.FromString,
+ options, channel_credentials,
+ insecure, call_credentials, compression, wait_for_ready, timeout, metadata)
diff --git a/src/recommendation/genproto/Dockerfile b/src/recommendation/genproto/Dockerfile
new file mode 100644
index 0000000..ad9b646
--- /dev/null
+++ b/src/recommendation/genproto/Dockerfile
@@ -0,0 +1,8 @@
+# Copyright The OpenTelemetry Authors
+# SPDX-License-Identifier: Apache-2.0
+
+FROM python:3.12-slim-bookworm
+
+WORKDIR /build
+
+RUN python -m pip install grpcio-tools==1.59.2
diff --git a/src/recommendation/logger.py b/src/recommendation/logger.py
new file mode 100644
index 0000000..0569665
--- /dev/null
+++ b/src/recommendation/logger.py
@@ -0,0 +1,28 @@
+#!/usr/bin/python
+
+# Copyright The OpenTelemetry Authors
+# SPDX-License-Identifier: Apache-2.0
+
+import logging
+import sys
+from pythonjsonlogger import jsonlogger
+from opentelemetry import trace
+
+
+class CustomJsonFormatter(jsonlogger.JsonFormatter):
+ def add_fields(self, log_record, record, message_dict):
+ super(CustomJsonFormatter, self).add_fields(log_record, record, message_dict)
+ if not log_record.get('otelTraceID'):
+ log_record['otelTraceID'] = trace.format_trace_id(trace.get_current_span().get_span_context().trace_id)
+ if not log_record.get('otelSpanID'):
+ log_record['otelSpanID'] = trace.format_span_id(trace.get_current_span().get_span_context().span_id)
+
+def getJSONLogger(name):
+ logger = logging.getLogger(name)
+ handler = logging.StreamHandler(sys.stdout)
+ formatter = CustomJsonFormatter('%(asctime)s %(levelname)s [%(name)s] [%(filename)s:%(lineno)d] [trace_id=%(otelTraceID)s span_id=%(otelSpanID)s] - %(message)s')
+ handler.setFormatter(formatter)
+ logger.addHandler(handler)
+ logger.setLevel(logging.INFO)
+ logger.propagate = False
+ return logger
diff --git a/src/recommendation/metrics.py b/src/recommendation/metrics.py
new file mode 100644
index 0000000..51b7996
--- /dev/null
+++ b/src/recommendation/metrics.py
@@ -0,0 +1,17 @@
+#!/usr/bin/python
+
+# Copyright The OpenTelemetry Authors
+# SPDX-License-Identifier: Apache-2.0
+
+def init_metrics(meter):
+
+ # Recommendations counter
+ app_recommendations_counter = meter.create_counter(
+ 'app_recommendations_counter', unit='recommendations', description="Counts the total number of given recommendations"
+ )
+
+ rec_svc_metrics = {
+ "app_recommendations_counter": app_recommendations_counter,
+ }
+
+ return rec_svc_metrics
diff --git a/src/recommendation/recommendation_server.py b/src/recommendation/recommendation_server.py
new file mode 100644
index 0000000..df681bf
--- /dev/null
+++ b/src/recommendation/recommendation_server.py
@@ -0,0 +1,173 @@
+#!/usr/bin/python
+
+# Copyright The OpenTelemetry Authors
+# SPDX-License-Identifier: Apache-2.0
+
+
+# Python
+import os
+import random
+from concurrent import futures
+
+# Pip
+import grpc
+from opentelemetry import trace, metrics
+from opentelemetry._logs import set_logger_provider
+from opentelemetry.exporter.otlp.proto.grpc._log_exporter import (
+ OTLPLogExporter,
+)
+from opentelemetry.sdk._logs import LoggerProvider, LoggingHandler
+from opentelemetry.sdk._logs.export import BatchLogRecordProcessor
+from opentelemetry.sdk.resources import Resource
+
+from openfeature import api
+from openfeature.contrib.provider.flagd import FlagdProvider
+
+from openfeature.contrib.hook.opentelemetry import TracingHook
+
+# Local
+import logging
+import demo_pb2
+import demo_pb2_grpc
+from grpc_health.v1 import health_pb2
+from grpc_health.v1 import health_pb2_grpc
+
+from metrics import (
+ init_metrics
+)
+
+cached_ids = []
+first_run = True
+
+class RecommendationService(demo_pb2_grpc.RecommendationServiceServicer):
+ def ListRecommendations(self, request, context):
+ prod_list = get_product_list(request.product_ids)
+ span = trace.get_current_span()
+ span.set_attribute("app.products_recommended.count", len(prod_list))
+ logger.info(f"Receive ListRecommendations for product ids:{prod_list}")
+
+ # build and return response
+ response = demo_pb2.ListRecommendationsResponse()
+ response.product_ids.extend(prod_list)
+
+ # Collect metrics for this service
+ rec_svc_metrics["app_recommendations_counter"].add(len(prod_list), {'recommendation.type': 'catalog'})
+
+ return response
+
+ def Check(self, request, context):
+ return health_pb2.HealthCheckResponse(
+ status=health_pb2.HealthCheckResponse.SERVING)
+
+ def Watch(self, request, context):
+ return health_pb2.HealthCheckResponse(
+ status=health_pb2.HealthCheckResponse.UNIMPLEMENTED)
+
+
+def get_product_list(request_product_ids):
+ global first_run
+ global cached_ids
+ with tracer.start_as_current_span("get_product_list") as span:
+ max_responses = 5
+
+ # Formulate the list of characters to list of strings
+ request_product_ids_str = ''.join(request_product_ids)
+ request_product_ids = request_product_ids_str.split(',')
+
+ # Feature flag scenario - Cache Leak
+ if check_feature_flag("recommendationCacheFailure"):
+ span.set_attribute("app.recommendation.cache_enabled", True)
+ if random.random() < 0.5 or first_run:
+ first_run = False
+ span.set_attribute("app.cache_hit", False)
+ logger.info("get_product_list: cache miss")
+ cat_response = product_catalog_stub.ListProducts(demo_pb2.Empty())
+ response_ids = [x.id for x in cat_response.products]
+ cached_ids = cached_ids + response_ids
+ cached_ids = cached_ids + cached_ids[:len(cached_ids) // 4]
+ product_ids = cached_ids
+ else:
+ span.set_attribute("app.cache_hit", True)
+ logger.info("get_product_list: cache hit")
+ product_ids = cached_ids
+ else:
+ span.set_attribute("app.recommendation.cache_enabled", False)
+ cat_response = product_catalog_stub.ListProducts(demo_pb2.Empty())
+ product_ids = [x.id for x in cat_response.products]
+
+ span.set_attribute("app.products.count", len(product_ids))
+
+ # Create a filtered list of products excluding the products received as input
+ filtered_products = list(set(product_ids) - set(request_product_ids))
+ num_products = len(filtered_products)
+ span.set_attribute("app.filtered_products.count", num_products)
+ num_return = min(max_responses, num_products)
+
+ # Sample list of indicies to return
+ indices = random.sample(range(num_products), num_return)
+ # Fetch product ids from indices
+ prod_list = [filtered_products[i] for i in indices]
+
+ span.set_attribute("app.filtered_products.list", prod_list)
+
+ return prod_list
+
+
+def must_map_env(key: str):
+ value = os.environ.get(key)
+ if value is None:
+ raise Exception(f'{key} environment variable must be set')
+ return value
+
+
+def check_feature_flag(flag_name: str):
+ # Initialize OpenFeature
+ client = api.get_client()
+ return client.get_boolean_value("recommendationCacheFailure", False)
+
+
+if __name__ == "__main__":
+ service_name = must_map_env('OTEL_SERVICE_NAME')
+ api.set_provider(FlagdProvider(host=os.environ.get('FLAGD_HOST', 'flagd'), port=os.environ.get('FLAGD_PORT', 8013)))
+ api.add_hooks([TracingHook()])
+
+ # Initialize Traces and Metrics
+ tracer = trace.get_tracer_provider().get_tracer(service_name)
+ meter = metrics.get_meter_provider().get_meter(service_name)
+ rec_svc_metrics = init_metrics(meter)
+
+ # Initialize Logs
+ logger_provider = LoggerProvider(
+ resource=Resource.create(
+ {
+ 'service.name': service_name,
+ }
+ ),
+ )
+ set_logger_provider(logger_provider)
+ log_exporter = OTLPLogExporter(insecure=True)
+ logger_provider.add_log_record_processor(BatchLogRecordProcessor(log_exporter))
+ handler = LoggingHandler(level=logging.NOTSET, logger_provider=logger_provider)
+
+ # Attach OTLP handler to logger
+ logger = logging.getLogger('main')
+ logger.addHandler(handler)
+
+ catalog_addr = must_map_env('PRODUCT_CATALOG_ADDR')
+ pc_channel = grpc.insecure_channel(catalog_addr)
+ product_catalog_stub = demo_pb2_grpc.ProductCatalogServiceStub(pc_channel)
+
+ # Create gRPC server
+ server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
+
+ # Add class to gRPC server
+ service = RecommendationService()
+ demo_pb2_grpc.add_RecommendationServiceServicer_to_server(service, server)
+ health_pb2_grpc.add_HealthServicer_to_server(service, server)
+
+ # Start server
+ port = must_map_env('RECOMMENDATION_PORT')
+ server.add_insecure_port(f'[::]:{port}')
+ server.start()
+ logger.info(f'Recommendation service started, listening on port {port}')
+ server.wait_for_termination()
diff --git a/src/recommendation/requirements.txt b/src/recommendation/requirements.txt
new file mode 100644
index 0000000..643cf8d
--- /dev/null
+++ b/src/recommendation/requirements.txt
@@ -0,0 +1,8 @@
+grpcio-health-checking==1.71.0
+openfeature-hooks-opentelemetry==0.2.0
+openfeature-provider-flagd==0.2.3
+opentelemetry-distro==0.58b0
+opentelemetry-exporter-otlp-proto-grpc==1.37.0
+psutil==7.0.0 # Importing this will also import opentelemetry-instrumentation-system-metrics when running opentelemetry-bootstrap
+python-dotenv==1.1.1
+python-json-logger==3.3.0