Add example for dapr grpc proxy mode (#414)

* Add example for dapr grpc proxy mode

Signed-off-by: hunter007 <wentao79@gmail.com>

* Modify README.md

Signed-off-by: hunter007 <wentao79@gmail.com>

---------

Signed-off-by: hunter007 <wentao79@gmail.com>
This commit is contained in:
hunter007 2023-06-06 12:00:37 +08:00 committed by GitHub
parent 10b832f741
commit effc2f0d3c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 217 additions and 11 deletions

View File

@ -90,6 +90,7 @@ jobs:
- name: Check Examples
run: |
cd examples
./validate.sh grpc-service
./validate.sh configuration
./validate.sh hello-world
./validate.sh pubsub

View File

@ -19,7 +19,7 @@ test:
./...
.PHONY: spell
spell: ## Checks spelling across the entire project
spell: ## Checks spelling across the entire project
@command -v misspell > /dev/null 2>&1 || (cd tools && go get github.com/client9/misspell/cmd/misspell)
@misspell -locale US -error go=golang client/**/* examples/**/* service/**/* actor/**/* .
@ -34,7 +34,7 @@ lint: ## Lints the entire project
golangci-lint run --timeout=3m
.PHONY: tag
tag: ## Creates release tag
tag: ## Creates release tag
git tag $(RELEASE_VERSION)
git push origin $(RELEASE_VERSION)

View File

@ -0,0 +1,64 @@
# Grpc Service Example with proxy mode
The `examples/grpc-service` folder contains a Dapr enabled `server` app and a `client` app that uses this SDK to invoke grpc methos via grpc stub, The `server` app is available as gRPC. The `client` app can target either one of these for service to service and binding invocations.
## Step
### Prepare
- Dapr installed
### Run server as a dapr app
<!-- STEP
name: Run grpc server with dapr proxy mode
output_match_mode: substring
expected_stdout_lines:
- 'Received: Dapr'
background: true
sleep: 15
-->
```bash
dapr run --app-id grpc-server \
--app-port 50051 \
--app-protocol grpc \
--dapr-grpc-port 50007 \
go run ./server/main.go
```
<!-- END_STEP -->
### Run grpc client
<!-- STEP
name: Run grpc client
expected_stdout_lines:
- 'Greeting: Hello Dapr'
output_match_mode: substring
background: true
sleep: 15
-->
```bash
dapr run --app-id grpc-client \
go run ./client/main.go
```
<!-- END_STEP -->
### Cleanup
<!-- STEP
expected_stdout_lines:
- '✅ app stopped successfully: grpc-server'
expected_stderr_lines:
name: Shutdown dapr
-->
```bash
dapr stop --app-id grpc-server
```
<!-- END_STEP -->

View File

@ -0,0 +1,36 @@
package main
import (
"context"
"log"
"time"
"google.golang.org/grpc"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
"google.golang.org/grpc/metadata"
)
const (
address = "localhost:50007"
)
func main() {
// Set up a connection to the server.
conn, err := grpc.Dial(address, grpc.WithInsecure(), grpc.WithBlock())
if err != nil {
log.Fatalf("did not connect: %v", err)
}
defer conn.Close()
c := pb.NewGreeterClient(conn)
ctx, cancel := context.WithTimeout(context.Background(), time.Second*2)
defer cancel()
ctx = metadata.AppendToOutgoingContext(ctx, "dapr-app-id", "grpc-server")
r, err := c.SayHello(ctx, &pb.HelloRequest{Name: "Dapr"})
if err != nil {
log.Fatalf("could not greet: %v", err)
}
log.Printf("Greeting: %s", r.GetMessage())
}

View File

@ -0,0 +1,20 @@
module github.com/dapr/go-sdk/examples/grpc-service
go 1.19
replace github.com/dapr/go-sdk => ../../
require (
github.com/dapr/go-sdk v0.0.0-00010101000000-000000000000
google.golang.org/grpc v1.55.0
google.golang.org/grpc/examples v0.0.0-20230602173802-c9d3ea567325
)
require (
github.com/golang/protobuf v1.5.3 // indirect
golang.org/x/net v0.10.0 // indirect
golang.org/x/sys v0.8.0 // indirect
golang.org/x/text v0.9.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 // indirect
google.golang.org/protobuf v1.30.0 // indirect
)

View File

@ -0,0 +1,26 @@
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/stretchr/testify v1.8.3 h1:RP3t2pwF7cMEbC1dqtB6poj3niw/9gnV4Cjg5oW5gtY=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19 h1:0nDDozoAU19Qb2HwhXadU8OcsiO/09cnTqhUtq2MEOM=
google.golang.org/genproto/googleapis/rpc v0.0.0-20230525234030-28d5490b6b19/go.mod h1:66JfowdXAEgad5O9NnYcsNPLCPZJD++2L9X0PCMODrA=
google.golang.org/grpc v1.55.0 h1:3Oj82/tFSCeUrRTg/5E/7d/W5A1tj6Ky1ABAuZuv5ag=
google.golang.org/grpc v1.55.0/go.mod h1:iYEXKGkEBhg1PjZQvoYEVPTDkHo1/bjTnfwTeGONTY8=
google.golang.org/grpc/examples v0.0.0-20230602173802-c9d3ea567325 h1:2RthLftQfQtpQMEmkGxDGs+PAG/sVWONfKd7km4DRzM=
google.golang.org/grpc/examples v0.0.0-20230602173802-c9d3ea567325/go.mod h1:JFf2mvgu0u96q6WJc59JQq9E9SQ6E93ML1ozmUNjW8k=
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.30.0 h1:kPPoIgf3TsEvrm0PFe15JQ+570QVxYzEvvHqChK+cng=
google.golang.org/protobuf v1.30.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

View File

@ -0,0 +1,42 @@
package main
import (
"context"
"log"
"net"
daprd "github.com/dapr/go-sdk/service/grpc"
"google.golang.org/grpc"
pb "google.golang.org/grpc/examples/helloworld/helloworld"
)
const (
port = ":50051"
)
// server is used to implement helloworld.GreeterServer.
type server struct {
pb.UnimplementedGreeterServer
}
// SayHello implements helloworld.GreeterServer
func (s *server) SayHello(ctx context.Context, in *pb.HelloRequest) (*pb.HelloReply, error) {
log.Printf("Received: %v", in.GetName())
return &pb.HelloReply{Message: "Hello " + in.GetName()}, nil
}
func main() {
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
s := grpc.NewServer()
pb.RegisterGreeterServer(s, &server{})
daprServer := daprd.NewServiceWithGrpcServer(lis, s)
// start the server
if err := daprServer.Start(); err != nil {
log.Fatalf("server error: %v", err)
}
}

View File

@ -6,7 +6,7 @@ Start by importing Dapr Go `service/grpc` package:
daprd "github.com/dapr/go-sdk/service/grpc"
```
## Creating and Starting Service
## Creating and Starting Service
To create a gRPC Dapr service, first, create a Dapr callback instance with a specific address:
@ -27,6 +27,23 @@ if err != nil {
s := daprd.NewServiceWithListener(list)
```
Dapr gRPC service supports using existed gRPC server with the help of `NewServiceWithGrpcServer`. You can use `RegisterGreeterServer` to add existed gRPC service either:
```go
lis, err := net.Listen("tcp", port)
if err != nil {
log.Fatalf("failed to listen: %v", err)
}
grpcServer := grpc.NewServer()
// register existed service
// pb.RegisterGreeterServer(grpcServer, &existedGrpcServer{})
// new dapr grpc service
s := daprd.NewServiceWithGrpcServer(lis, grpcServer)
```
Once you create a service instance, you can "attach" to that service any number of event, binding, and service invocation logic handlers as shown below. Onces the logic is defined, you are ready to start the service:
```go
@ -36,7 +53,7 @@ if err := s.Start(); err != nil {
```
## Event Handling
## Event Handling
To handle events from specific topic you need to add at least one topic event handler before starting the service:
@ -60,9 +77,9 @@ func eventHandler(ctx context.Context, e *common.TopicEvent) (retry bool, err er
}
```
## Service Invocation Handler
## Service Invocation Handler
To handle service invocations you will need to add at least one service invocation handler before starting the service:
To handle service invocations you will need to add at least one service invocation handler before starting the service:
```go
if err := s.AddServiceInvocationHandler("echo", echoHandler); err != nil {
@ -75,7 +92,7 @@ The handler method itself can be any method with the expected signature:
```go
func echoHandler(ctx context.Context, in *common.InvocationEvent) (out *common.Content, err error) {
log.Printf("echo - ContentType:%s, Verb:%s, QueryString:%s, %+v", in.ContentType, in.Verb, in.QueryString, string(in.Data))
// do something with the invocation here
// do something with the invocation here
out = &common.Content{
Data: in.Data,
ContentType: in.ContentType,
@ -85,9 +102,9 @@ func echoHandler(ctx context.Context, in *common.InvocationEvent) (out *common.C
}
```
## Binding Invocation Handler
## Binding Invocation Handler
To handle binding invocations you will need to add at least one binding invocation handler before starting the service:
To handle binding invocations you will need to add at least one binding invocation handler before starting the service:
```go
if err := s.AddBindingInvocationHandler("run", runHandler); err != nil {
@ -100,12 +117,12 @@ The handler method itself can be any method with the expected signature:
```go
func runHandler(ctx context.Context, in *common.BindingEvent) (out []byte, err error) {
log.Printf("binding - Data:%v, Meta:%v", in.Data, in.Metadata)
// do something with the invocation here
// do something with the invocation here
return nil, nil
}
```
## Templates
## Templates
To accelerate your gRPC Dapr app development in Go even further you can use one of the GitHub templates integrating the gRPC Dapr callback package: