From 4ac66b072a311a8ca0b2a154d7fd11ecc45adfea Mon Sep 17 00:00:00 2001 From: Simon Zeltser Date: Thu, 28 Jun 2018 17:12:33 -0700 Subject: [PATCH] Refactored the cart service to add more telemetry 1. Added more telemetry around starting redis cache 2. Now if you don't specify redis cache address via command line or environment variable, it will run with local cart (no redis). This is useful for debugging purposes --- src/cartservice/Program.cs | 57 +++++++++++++++------ src/cartservice/cartstore/LocalCartStore.cs | 7 +++ src/cartservice/cartstore/RedisCartStore.cs | 13 +++-- src/cartservice/interfaces/ICartStore.cs | 2 + src/cartservice/scripts/docker_setup.bat | 8 +-- 5 files changed, 63 insertions(+), 24 deletions(-) diff --git a/src/cartservice/Program.cs b/src/cartservice/Program.cs index ead7546..b0a4d1e 100644 --- a/src/cartservice/Program.cs +++ b/src/cartservice/Program.cs @@ -3,6 +3,7 @@ using System.IO; using System.Threading; using System.Threading.Tasks; using cartservice.cartstore; +using cartservice.interfaces; using CommandLine; using Grpc.Core; using Microsoft.Extensions.Configuration; @@ -28,22 +29,23 @@ namespace cartservice public string Redis { get; set; } } - static object StartServer(string host, int port, string redisAddress) + static object StartServer(string host, int port, ICartStore cartStore) { // Run the server in a separate thread and make the main thread busy waiting. // The busy wait is because when we run in a container, we can't use techniques such as waiting on user input (Console.Readline()) - Task.Run(() => + Task.Run(async () => { - //var store = new LocalCartStore(); - var store = new RedisCartStore(redisAddress); + Console.WriteLine($"Trying to start a grpc server at {host}:{port}"); Server server = new Server { - Services = { Hipstershop.CartService.BindService(new CartServiceImpl(store)) }, + Services = { Hipstershop.CartService.BindService(new CartServiceImpl(cartStore)) }, Ports = { new ServerPort(host, port, ServerCredentials.Insecure) } }; Console.WriteLine($"Cart server is listening at {host}:{port}"); server.Start(); + + await cartStore.InitializeAsync(); }); // Busy wait to keep the process alive @@ -75,8 +77,8 @@ namespace cartservice hostname = Environment.GetEnvironmentVariable(CART_SERVICE_ADDRESS); if (string.IsNullOrEmpty(hostname)) { - Console.WriteLine($"Environment variable {CART_SERVICE_ADDRESS} was not set. Setting the host to 127.0.0.1"); - hostname = "127.0.0.1"; + Console.WriteLine($"Environment variable {CART_SERVICE_ADDRESS} was not set. Setting the host to 0.0.0.0"); + hostname = "0.0.0.0"; } } @@ -98,19 +100,23 @@ namespace cartservice } // Set redis cache host (hostname+port) - string redis = options.Redis; - if (string.IsNullOrEmpty(redis)) + ICartStore cartStore; + string redis = ReadRedisAddress(options.Redis); + + // Redis was specified via command line or environment variable + if (!string.IsNullOrEmpty(redis)) { - Console.WriteLine($"Reading redis cache address from environment variable {REDIS_ADDRESS}"); - redis = Environment.GetEnvironmentVariable(REDIS_ADDRESS); - if (string.IsNullOrEmpty(redis)) - { - Console.WriteLine("Redis cache host(hostname+port) was not specified. It should be specified via command line or REDIS_ADDRESS environment variable."); - return -1; - } + cartStore = new RedisCartStore(redis); + return StartServer(hostname, port, cartStore); + } + else + { + Console.WriteLine("Redis cache host(hostname+port) was not specified. Starting a cart service using local store"); + Console.WriteLine("If you wanted to use Redis Cache as a backup store, you should provide its address via command line or REDIS_ADDRESS environment variable."); + cartStore = new LocalCartStore(); } - return StartServer(hostname, port, redis); + return StartServer(hostname, port, cartStore); }, errs => 1); break; @@ -119,5 +125,22 @@ namespace cartservice break; } } + + private static string ReadRedisAddress(string address) + { + if (!string.IsNullOrEmpty(address)) + { + return address; + } + + Console.WriteLine($"Reading redis cache address from environment variable {REDIS_ADDRESS}"); + string redis = Environment.GetEnvironmentVariable(REDIS_ADDRESS); + if (!string.IsNullOrEmpty(redis)) + { + return redis; + } + + return null; + } } } diff --git a/src/cartservice/cartstore/LocalCartStore.cs b/src/cartservice/cartstore/LocalCartStore.cs index 3a63de8..7ff5f61 100644 --- a/src/cartservice/cartstore/LocalCartStore.cs +++ b/src/cartservice/cartstore/LocalCartStore.cs @@ -11,6 +11,13 @@ namespace cartservice.cartstore // Maps between user and their cart private ConcurrentDictionary userCartItems = new ConcurrentDictionary(); + public Task InitializeAsync() + { + Console.WriteLine("Local Cart Store was initialized"); + + return Task.CompletedTask; + } + public Task AddItemAsync(string userId, string productId, int quantity) { Console.WriteLine($"AddItemAsync called with userId={userId}, productId={productId}, quantity={quantity}"); diff --git a/src/cartservice/cartstore/RedisCartStore.cs b/src/cartservice/cartstore/RedisCartStore.cs index 87adb2c..50f1f6f 100644 --- a/src/cartservice/cartstore/RedisCartStore.cs +++ b/src/cartservice/cartstore/RedisCartStore.cs @@ -13,9 +13,10 @@ namespace cartservice.cartstore { private const string CART_FIELD_NAME = "cart"; - private readonly ConnectionMultiplexer redis; + private static ConnectionMultiplexer redis; private readonly byte[] emptyCartBytes; + private readonly string connectionString; public RedisCartStore(string redisAddress) { @@ -23,9 +24,15 @@ namespace cartservice.cartstore var cart = new Hipstershop.Cart(); emptyCartBytes = cart.ToByteArray(); - string connectionString = $"{redisAddress},ssl=false,allowAdmin=true"; + connectionString = $"{redisAddress},ssl=false,allowAdmin=true"; + Console.WriteLine($"Going to use Redis cache at this address: {connectionString}"); + } + + public async Task InitializeAsync() + { Console.WriteLine("Connecting to Redis: " + connectionString); - redis = ConnectionMultiplexer.Connect(connectionString); + redis = await ConnectionMultiplexer.ConnectAsync(connectionString, Console.Out); + Console.WriteLine("Connected successfully to Redis"); } public async Task AddItemAsync(string userId, string productId, int quantity) diff --git a/src/cartservice/interfaces/ICartStore.cs b/src/cartservice/interfaces/ICartStore.cs index f4fa1e5..ae9702a 100644 --- a/src/cartservice/interfaces/ICartStore.cs +++ b/src/cartservice/interfaces/ICartStore.cs @@ -4,6 +4,8 @@ namespace cartservice.interfaces { internal interface ICartStore { + Task InitializeAsync(); + Task AddItemAsync(string userId, string productId, int quantity); Task EmptyCartAsync(string userId); diff --git a/src/cartservice/scripts/docker_setup.bat b/src/cartservice/scripts/docker_setup.bat index b841758..f5856a9 100644 --- a/src/cartservice/scripts/docker_setup.bat +++ b/src/cartservice/scripts/docker_setup.bat @@ -9,7 +9,7 @@ GOTO End1 :local set REDIS_PORT=6379 set REDIS_ADDR=localhost:%REDIS_PORT% - set LISTEN_ADDR=127.0.0.1 + set LISTEN_ADDR=0.0.0.0 set PORT=7070 echo running redis emulator locally on a separate window @@ -23,12 +23,12 @@ GOTO End1 :docker_local set REDIS_PORT=6379 - set REDIS_ADDR=redis:%REDIS_PORT% - set LISTEN_ADDR=127.0.0.1 + set REDIS_ADDR=0.0.0.0:%REDIS_PORT% + set LISTEN_ADDR=0.0.0.0 set PORT=7070 echo run docker container with redis - docker run -d --name=redis -p %REDIS_PORT%:%REDIS_PORT% redis + start docker run -d --name=redis -p %REDIS_PORT%:%REDIS_PORT% redis echo building container image for cart service docker build -t cartservice ..\.