-
-
Notifications
You must be signed in to change notification settings - Fork 101
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
initial readme for grpc project (#51)
* initial readme for grpc project * Update README.md * Update README.md * Initial version of grpc project * Initial version of grpc project * Initial version of grpc project * Update README.md * Update README.md * Updated: added skeleton code and proto * comments * fix * few more points * fixes * fix * Update grpc-client-server/prober_client/main.go Co-authored-by: Daniel Wagner-Hall <[email protected]> * Update grpc-client-server/README.md Co-authored-by: Daniel Wagner-Hall <[email protected]> * Update grpc-client-server/README.md Co-authored-by: Daniel Wagner-Hall <[email protected]> * Update grpc-client-server/README.md Co-authored-by: Daniel Wagner-Hall <[email protected]> * Update grpc-client-server/README.md Co-authored-by: Daniel Wagner-Hall <[email protected]> * Update grpc-client-server/README.md Co-authored-by: Daniel Wagner-Hall <[email protected]> * Update grpc-client-server/README.md Co-authored-by: Daniel Wagner-Hall <[email protected]> * Update grpc-client-server/README.md Co-authored-by: Daniel Wagner-Hall <[email protected]> * Update grpc-client-server/README.md Co-authored-by: Daniel Wagner-Hall <[email protected]> * Update README.md * Update grpc-client-server/prober_client/main.go Co-authored-by: Daniel Wagner-Hall <[email protected]> Co-authored-by: Daniel Wagner-Hall <[email protected]>
- Loading branch information
1 parent
3b050f5
commit 79c2fed
Showing
7 changed files
with
358 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,3 @@ | ||
!*/assets | ||
.DS_Store | ||
!*/assets | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
# GRPC Client and Server Communication | ||
|
||
Timebox: 3 days | ||
|
||
Learning objectives: | ||
* Learn what gRPC is and how it differs from HTTP | ||
* Understand what kinds of issues can occur in a real system and how to defend against them | ||
* Learn what observability is, and what are some kinds of observability you'd find in use in production? | ||
|
||
## What is gRPC? | ||
|
||
We've used simple HTTP request so far, making and handling GET and POST requests. | ||
|
||
RPC is another way to communicate between clients and servers (or frontends and backends). | ||
|
||
It is used commonly within an organisation (it isn't used from browsers), where it has advantages around types, performance, and streaming. | ||
|
||
gRPC is not used to communicate from web browsers to servers (important because this is context they have). | ||
|
||
RPCs let you call a specific function on another computer. RPCs are highly structured; normally the request and response are encoded in efficient binary formats which are not human-readable. HTTP APIs are usually limited to CRUD (Create, Read, Update, Delete) operations and RPCs can perform any kind of operation. | ||
|
||
If you want to efficiently integrate two systems that you control, RPCs are a good choice. If you want to provide an API for use by developers outside of your organisation then HTTP APIs are generally a better choice, because they are simpler to develop against, all programming languages provide good HTTP support, and HTTP works in the browser. | ||
|
||
gRPC, which we will use in this exercise, is a RPC implementation that is fairly common in industry. | ||
|
||
Read the [gRPC Introduction](https://grpc.io/docs/what-is-grpc/introduction/) and | ||
[gRPC Core Concepts](https://grpc.io/docs/what-is-grpc/core-concepts/) for an overview of gRPC. | ||
|
||
## Run the gRPC Quick Start Hello World Example | ||
|
||
Run through the [gRPC Hello World example](https://grpc.io/docs/languages/go/quickstart/) from the grpc.io documentation. | ||
|
||
This will ensure you have the right tools on your machine and working correctly. | ||
|
||
## Build a gRPC based prober | ||
|
||
Next, we will implement a simple prober service. Imagine that we want to verify that our site is available and has acceptable latency from many different locations around the world. We build a program that performs HTTP GETs on a provided endpoint and returns statistics about how long it took. | ||
|
||
In a real production system, we could run several instances of our prober server in different regions and use one client to query all of the prober servers. | ||
|
||
In the same directory as this README you will find initial versions of: | ||
* the protocol buffer definition | ||
* prober server Go code | ||
* prober client Go code | ||
|
||
Generate the generated protobuf code: | ||
```console | ||
> protoc --go_out=. --go_opt=paths=source_relative \ | ||
--go-grpc_out=. --go-grpc_opt=paths=source_relative \ | ||
prober/prober.proto | ||
``` | ||
|
||
Observe the new generated files: | ||
```console | ||
> ls prober | ||
> prober.pb.go prober.proto prober_grpc.pb.go | ||
``` | ||
|
||
Read through `prober_grpc.pb.go` - this is the interface we will use in our code. This is how gRPC works: a `proto` format | ||
gets generated into language-specific code that we can use to interact with gRPCs. If we're working with multiple programming languages | ||
that need to interact through RPCs, we can do this by generating from the same protocol buffer definition with the language-specific | ||
tooling. | ||
|
||
Now run the server and client code. You should see output like this. | ||
|
||
```console | ||
> go run prober_server/main.go | ||
> 2022/10/19 17:51:32 server listening at [::]:50051 | ||
```` | ||
|
||
```console | ||
> go run prober_client/main.go | ||
> 2022/10/19 17:52:15 Response Time: 117.000000 | ||
``` | ||
|
||
We've now gained some experience with the protocol buffer format, learned | ||
how to generate Go code from protocol buffer definitions, and called that code from Go programs. | ||
|
||
## Implement prober logic | ||
|
||
Let's modify the prober service slightly. Instead of the simple one-off HTTP GET against a hardcoded google.com, we are going to modify the service to probe an HTTP endpoint N times and return the average time to GET that endpoint to the client. | ||
|
||
Change your prober request and response: | ||
* Add a field to the `ProbeRequest` for the number of requests to make. | ||
* Rename the field in `ProbeReply` (and perhaps add a comment) to make clear it's the _average_ response time of the several requests. | ||
|
||
Note that it's ok to rename fields in protobuf (unlike when we use JSON), because the binary encoding of protobuf messages doesn't include field names. You can [read more about backward/forward compatibility with protobufs](https://earthly.dev/blog/backward-and-forward-compatibility/) if you want. | ||
|
||
Remember that you'll need to re-generate your Go code after changing your proto definitions. | ||
|
||
Update your client to read the endpoint and number of repetitions from the [command line](https://gobyexample.com/command-line-arguments). | ||
Then update your server to execute the probe: do a HTTP fetch of `endpoint` the specified number of times. | ||
The initial version of the code demonstrates how to use the standard [`net/http` package](https://pkg.go.dev/net/http) and the standard time package. | ||
|
||
Add up all the elapsed times, divide by the number of repetitions, and return the average to the client. | ||
The client should print out the average value received. | ||
You can do arithmetic operations like addition and division on `time.Duration` values in Go. | ||
|
||
## Add a client timeout | ||
|
||
Maybe the site we are probing is very slow (which can happen for all kinds of reasons, from network problems to excessive load), | ||
or perhaps the number of repetitions is very high. | ||
Either way, we never want our program to wait forever. | ||
If we are not careful about preventing this then we can end up building systems where problems in one small part of the system | ||
spread across all of the services that talk to that part of the system. | ||
|
||
On the client side, add a [timeout](https://pkg.go.dev/context#WithTimeout) to stop waiting after 1 second. | ||
|
||
Run your client against some website - how many repetitions do you need to see your client timeout? | ||
|
||
## Handling Errors | ||
|
||
How do we know if the HTTP fetch succeeded at the server? Add a check to make sure it did. | ||
|
||
How should we deal with errors, e.g. if the endpoint isn't found, or says the server is in an error state? | ||
Modify your code and proto format to handle these cases. | ||
|
||
## Extra Challenge: Serve and Collect Prometheus Metrics | ||
|
||
These sections are optional - do them for an extra challenge if time permits. | ||
|
||
### Part 1: Add Prometheus Metrics | ||
Let's learn something about how to monitor applications. | ||
|
||
In software operations, we want to know what our software is doing and how it is performing. | ||
One very useful technique is to have our program export metrics. Metrics are basically values that your | ||
program makes available (the industry standard is to export and scrape over HTTP). | ||
|
||
Specialised programs, such as Prometheus, can then fetch metrics regularly | ||
from all the running instances of your program, store the history of these metrics, and do useful arithmetic on them | ||
(like computing rates, averages, and maximums). We can use this data to do troubleshooting and to alert if things | ||
go wrong. | ||
|
||
Read the [Overview of Prometheus](https://prometheus.io/docs/introduction/overview/). | ||
|
||
Now add Prometheus metrics to your prober server. Every time you execute a probe, update a `gauge` metric that tracks the latency. | ||
Add a `label` specifying the endpoint being probed. | ||
The [Prometheus Guide to Instrumenting a Go Application](https://prometheus.io/docs/guides/go-application/) has all the information you need to do this. | ||
|
||
Once you've run your program, use your client to execute probes against some endpoint. | ||
Now use the `curl` program or your browser to view the metrics. | ||
You should see a number of built-in Go metrics, plus your new gauge. | ||
|
||
If you use your client to start probing a second endpoint, you should see a second labelled metric appear. | ||
|
||
### Part 2: Scrape Prometheus Metrics | ||
The final step is to set up the Prometheus application to periodically pull metrics from your `prober_server`. | ||
|
||
The easiest way to run Prometheus locally is in Docker. This way we can run an up-to-date version that has been built by the Prometheus maintainers. | ||
See [Prometheus Installation](https://prometheus.io/docs/prometheus/latest/installation/). | ||
|
||
You'll need to set up a simple configuration to scrape your `prober_server`. Prometheus [configuration](https://prometheus.io/docs/prometheus/latest/configuration/configuration/) is quite complex but you can adapt this [example configuration](https://github.com/prometheus/prometheus/blob/main/documentation/examples/prometheus.yml). | ||
|
||
Next, find your custom gauge metric from your `prober_server` in http://localhost:9090/metrics. | ||
Graph it in http://localhost:9090/graph. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
module github.com/CodeYourFuture/immersive-go-course/grpc-client-server | ||
|
||
go 1.19 | ||
|
||
require ( | ||
github.com/golang/protobuf v1.5.2 // indirect | ||
golang.org/x/net v0.0.0-20201021035429-f5854403a974 // indirect | ||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 // indirect | ||
golang.org/x/text v0.3.3 // indirect | ||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect | ||
google.golang.org/grpc v1.50.1 // indirect | ||
google.golang.org/protobuf v1.27.1 // indirect | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= | ||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= | ||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= | ||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= | ||
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= | ||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= | ||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= | ||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= | ||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | ||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= | ||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= | ||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= | ||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= | ||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= | ||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= | ||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= | ||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= | ||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw= | ||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY= | ||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= | ||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= | ||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= | ||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | ||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= | ||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= | ||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= | ||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= | ||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= | ||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= | ||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= | ||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= | ||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= | ||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= | ||
golang.org/x/net v0.0.0-20201021035429-f5854403a974 h1:IX6qOQeG5uLjB/hjjwjedwfjND0hgjPMMyO1RoIXQNI= | ||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= | ||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | ||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | ||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | ||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4 h1:myAQVi0cGEoqQVR5POX+8RR2mrocKqNN1hmeMqhX27k= | ||
golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | ||
golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= | ||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | ||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= | ||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= | ||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= | ||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= | ||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= | ||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= | ||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= | ||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= | ||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= | ||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 h1:+kGHl1aib/qcwaRi1CbqBZ1rk19r85MNUf8HaBghugY= | ||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= | ||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= | ||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= | ||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= | ||
google.golang.org/grpc v1.50.1 h1:DS/BukOZWp8s6p4Dt/tOaJaTQyPyOoCcrjroHuCeLzY= | ||
google.golang.org/grpc v1.50.1/go.mod h1:ZgQEeidpAuNRZ8iRrlBKXZQP1ghovWIVhdJRyCDK+GI= | ||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= | ||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= | ||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= | ||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= | ||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= | ||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= | ||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= | ||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= | ||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= | ||
google.golang.org/protobuf v1.27.1 h1:SnqbnDw1V7RiZcXPx5MEeqPv2s79L9i7BJUlG/+RurQ= | ||
google.golang.org/protobuf v1.27.1/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc= | ||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= | ||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
syntax = "proto3"; | ||
|
||
option go_package = "github.com/CodeYourFuture/immersive-go-course/grpc-client-server/prober"; | ||
|
||
package prober; | ||
|
||
// The prober service definition. | ||
service Prober { | ||
rpc DoProbes (ProbeRequest) returns (ProbeReply) {} | ||
} | ||
|
||
// The request message | ||
message ProbeRequest { | ||
string endpoint = 1; | ||
} | ||
|
||
// The response message containing the result | ||
message ProbeReply { | ||
float result = 1; | ||
} | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
// Package main implements a client for Prober service. | ||
package main | ||
|
||
import ( | ||
"context" | ||
"flag" | ||
"log" | ||
|
||
pb "github.com/CodeYourFuture/immersive-go-course/grpc-client-server/prober" | ||
"google.golang.org/grpc" | ||
"google.golang.org/grpc/credentials/insecure" | ||
) | ||
|
||
var ( | ||
addr = flag.String("addr", "localhost:50051", "the address to connect to") | ||
) | ||
|
||
func main() { | ||
flag.Parse() | ||
// Set up a connection to the server. | ||
conn, err := grpc.Dial(*addr, grpc.WithTransportCredentials(insecure.NewCredentials())) | ||
if err != nil { | ||
log.Fatalf("did not connect: %v", err) | ||
} | ||
defer conn.Close() | ||
c := pb.NewProberClient(conn) | ||
|
||
// Contact the server and print out its response. | ||
ctx := context.Background() // TODO: add a timeout | ||
|
||
// TODO: endpoint should be a flag | ||
// TODO: add number of times to probe | ||
r, err := c.DoProbes(ctx, &pb.ProbeRequest{Endpoint: "http://www.google.com"}) | ||
if err != nil { | ||
log.Fatalf("could not probe: %v", err) | ||
} | ||
log.Printf("Response Time: %f", r.GetResult()) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
package main | ||
|
||
import ( | ||
"context" | ||
"flag" | ||
"fmt" | ||
"log" | ||
"net" | ||
"net/http" | ||
"time" | ||
|
||
pb "github.com/CodeYourFuture/immersive-go-course/grpc-client-server/prober" | ||
"google.golang.org/grpc" | ||
) | ||
|
||
var ( | ||
port = flag.Int("port", 50051, "The server port") | ||
) | ||
|
||
// server is used to implement prober.ProberServer. | ||
type server struct { | ||
pb.UnimplementedProberServer | ||
} | ||
|
||
func (s *server) DoProbes(ctx context.Context, in *pb.ProbeRequest) (*pb.ProbeReply, error) { | ||
// TODO: support a number of repetitions and return average latency | ||
start := time.Now() | ||
_, _ = http.Get(in.GetEndpoint()) // TODO: add error handling here and check the response code | ||
elapsed := time.Since(start) | ||
elapsedMsecs := float32(elapsed / time.Millisecond) | ||
|
||
return &pb.ProbeReply{Result: elapsedMsecs}, nil | ||
} | ||
|
||
func main() { | ||
flag.Parse() | ||
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", *port)) | ||
if err != nil { | ||
log.Fatalf("failed to listen: %v", err) | ||
} | ||
s := grpc.NewServer() | ||
pb.RegisterProberServer(s, &server{}) | ||
log.Printf("server listening at %v", lis.Addr()) | ||
if err := s.Serve(lis); err != nil { | ||
log.Fatalf("failed to serve: %v", err) | ||
} | ||
} |