forked from GoogleCloudPlatform/microservices-demo
-
Notifications
You must be signed in to change notification settings - Fork 7
/
Program.cs
183 lines (160 loc) · 7.6 KB
/
Program.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
// Copyright 2018 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
using System;
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;
namespace cartservice
{
class Program
{
const string CART_SERVICE_ADDRESS = "LISTEN_ADDR";
const string REDIS_ADDRESS = "REDIS_ADDR";
const string CART_SERVICE_PORT = "PORT";
[Verb("start", HelpText = "Starts the server listening on provided port")]
class ServerOptions
{
[Option('h', "hostname", HelpText = "The ip on which the server is running. If not provided, LISTEN_ADDR environment variable value will be used. If not defined, localhost is used")]
public string Host { get; set; }
[Option('p', "port", HelpText = "The port on for running the server")]
public int Port { get; set; }
[Option('r', "redis", HelpText = "The ip of redis cache")]
public string Redis { get; set; }
}
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 serverTask = Task.Run(async () =>
{
try
{
await cartStore.InitializeAsync();
Console.WriteLine($"Trying to start a grpc server at {host}:{port}");
Server server = new Server
{
Services =
{
// Cart Service Endpoint
Hipstershop.CartService.BindService(new CartServiceImpl(cartStore)),
// Health Endpoint
Grpc.Health.V1.Health.BindService(new HealthImpl(cartStore))
},
Ports = { new ServerPort(host, port, ServerCredentials.Insecure) }
};
Console.WriteLine($"Cart server is listening at {host}:{port}");
server.Start();
Console.WriteLine("Initialization completed");
// Keep the server up and running
while(true)
{
Thread.Sleep(TimeSpan.FromMinutes(10));
}
}
catch (Exception ex)
{
Console.WriteLine(ex);
}
});
return Task.WaitAny(new[] { serverTask });
}
static void Main(string[] args)
{
if (args.Length == 0)
{
Console.WriteLine("Invalid number of arguments supplied");
Environment.Exit(-1);
}
switch (args[0])
{
case "start":
Parser.Default.ParseArguments<ServerOptions>(args).MapResult(
(ServerOptions options) =>
{
Console.WriteLine($"Started as process with id {System.Diagnostics.Process.GetCurrentProcess().Id}");
// Set hostname/ip address
string hostname = options.Host;
if (string.IsNullOrEmpty(hostname))
{
Console.WriteLine($"Reading host address from {CART_SERVICE_ADDRESS} environment variable");
hostname = Environment.GetEnvironmentVariable(CART_SERVICE_ADDRESS);
if (string.IsNullOrEmpty(hostname))
{
Console.WriteLine($"Environment variable {CART_SERVICE_ADDRESS} was not set. Setting the host to 0.0.0.0");
hostname = "0.0.0.0";
}
}
// Set the port
int port = options.Port;
if (options.Port <= 0)
{
Console.WriteLine($"Reading cart service port from {CART_SERVICE_PORT} environment variable");
string portStr = Environment.GetEnvironmentVariable(CART_SERVICE_PORT);
if (string.IsNullOrEmpty(portStr))
{
Console.WriteLine($"{CART_SERVICE_PORT} environment variable was not set. Setting the port to 8080");
port = 8080;
}
else
{
port = int.Parse(portStr);
}
}
// Set redis cache host (hostname+port)
ICartStore cartStore;
string redis = ReadRedisAddress(options.Redis);
// Redis was specified via command line or environment variable
if (!string.IsNullOrEmpty(redis))
{
// If you want to start cart store using local cache in process, you can replace the following line with this:
// cartStore = new LocalCartStore();
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, cartStore);
},
errs => 1);
break;
default:
Console.WriteLine("Invalid command");
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;
}
}
}