Skip to content

Commit 7320113

Browse files
committed
feature: grpc_interceptor example
Signed-off-by: Valery Piashchynski <piashchynski.valery@gmail.com>
1 parent 88d5538 commit 7320113

5 files changed

Lines changed: 167 additions & 1 deletion

File tree

go.mod

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,14 @@ require (
99
github.com/roadrunner-server/endure/v2 v2.6.2
1010
github.com/roadrunner-server/errors v1.4.1
1111
go.uber.org/zap v1.27.1
12+
google.golang.org/grpc v1.79.1
1213
)
1314

14-
require go.uber.org/multierr v1.11.0 // indirect
15+
require (
16+
go.uber.org/multierr v1.11.0 // indirect
17+
golang.org/x/net v0.48.0 // indirect
18+
golang.org/x/sys v0.39.0 // indirect
19+
golang.org/x/text v0.32.0 // indirect
20+
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 // indirect
21+
google.golang.org/protobuf v1.36.10 // indirect
22+
)

go.sum

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,17 @@
1+
github.com/cespare/xxhash/v2 v2.3.0 h1:UL815xU9SqsFlibzuggzjXhog7bL6oX9BbNZnL2UFvs=
2+
github.com/cespare/xxhash/v2 v2.3.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
13
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
24
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
5+
github.com/go-logr/logr v1.4.3 h1:CjnDlHq8ikf6E492q6eKboGOC0T8CDaOvkHCIg8idEI=
6+
github.com/go-logr/logr v1.4.3/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
7+
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
8+
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
9+
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
10+
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
11+
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
12+
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
13+
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
14+
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
315
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
416
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
517
github.com/roadrunner-server/api/v4 v4.23.0 h1:lrVXgP4ozD/H5DrIdT181ldVhD1R9QT5qsi8qWUTDF4=
@@ -10,11 +22,37 @@ github.com/roadrunner-server/errors v1.4.1 h1:LKNeaCGiwd3t8IaL840ZNF3UA9yDQlpvHn
1022
github.com/roadrunner-server/errors v1.4.1/go.mod h1:qeffnIKG0e4j1dzGpa+OGY5VKSfMphizvqWIw8s2lAo=
1123
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
1224
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
25+
go.opentelemetry.io/auto/sdk v1.2.1 h1:jXsnJ4Lmnqd11kwkBV2LgLoFMZKizbCi5fNZ/ipaZ64=
26+
go.opentelemetry.io/auto/sdk v1.2.1/go.mod h1:KRTj+aOaElaLi+wW1kO/DZRXwkF4C5xPbEe3ZiIhN7Y=
27+
go.opentelemetry.io/otel v1.39.0 h1:8yPrr/S0ND9QEfTfdP9V+SiwT4E0G7Y5MO7p85nis48=
28+
go.opentelemetry.io/otel v1.39.0/go.mod h1:kLlFTywNWrFyEdH0oj2xK0bFYZtHRYUdv1NklR/tgc8=
29+
go.opentelemetry.io/otel/metric v1.39.0 h1:d1UzonvEZriVfpNKEVmHXbdf909uGTOQjA0HF0Ls5Q0=
30+
go.opentelemetry.io/otel/metric v1.39.0/go.mod h1:jrZSWL33sD7bBxg1xjrqyDjnuzTUB0x1nBERXd7Ftcs=
31+
go.opentelemetry.io/otel/sdk v1.39.0 h1:nMLYcjVsvdui1B/4FRkwjzoRVsMK8uL/cj0OyhKzt18=
32+
go.opentelemetry.io/otel/sdk v1.39.0/go.mod h1:vDojkC4/jsTJsE+kh+LXYQlbL8CgrEcwmt1ENZszdJE=
33+
go.opentelemetry.io/otel/sdk/metric v1.39.0 h1:cXMVVFVgsIf2YL6QkRF4Urbr/aMInf+2WKg+sEJTtB8=
34+
go.opentelemetry.io/otel/sdk/metric v1.39.0/go.mod h1:xq9HEVH7qeX69/JnwEfp6fVq5wosJsY1mt4lLfYdVew=
35+
go.opentelemetry.io/otel/trace v1.39.0 h1:2d2vfpEDmCJ5zVYz7ijaJdOF59xLomrvj7bjt6/qCJI=
36+
go.opentelemetry.io/otel/trace v1.39.0/go.mod h1:88w4/PnZSazkGzz/w84VHpQafiU4EtqqlVdxWy+rNOA=
1337
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
1438
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
1539
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
1640
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
1741
go.uber.org/zap v1.27.1 h1:08RqriUEv8+ArZRYSTXy1LeBScaMpVSTBhCeaZYfMYc=
1842
go.uber.org/zap v1.27.1/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
43+
golang.org/x/net v0.48.0 h1:zyQRTTrjc33Lhh0fBgT/H3oZq9WuvRR5gPC70xpDiQU=
44+
golang.org/x/net v0.48.0/go.mod h1:+ndRgGjkh8FGtu1w1FGbEC31if4VrNVMuKTgcAAnQRY=
45+
golang.org/x/sys v0.39.0 h1:CvCKL8MeisomCi6qNZ+wbb0DN9E5AATixKsvNtMoMFk=
46+
golang.org/x/sys v0.39.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks=
47+
golang.org/x/text v0.32.0 h1:ZD01bjUt1FQ9WJ0ClOL5vxgxOI/sVCNgX1YtKwcY0mU=
48+
golang.org/x/text v0.32.0/go.mod h1:o/rUWzghvpD5TXrTIBuJU77MTaN0ljMWE47kxGJQ7jY=
49+
gonum.org/v1/gonum v0.16.0 h1:5+ul4Swaf3ESvrOnidPp4GZbzf0mxVQpDCYUQE7OJfk=
50+
gonum.org/v1/gonum v0.16.0/go.mod h1:fef3am4MQ93R2HHpKnLk4/Tbh/s0+wqD5nfa6Pnwy4E=
51+
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217 h1:gRkg/vSppuSQoDjxyiGfN4Upv/h/DQmIR10ZU8dh4Ww=
52+
google.golang.org/genproto/googleapis/rpc v0.0.0-20251202230838-ff82c1b0f217/go.mod h1:7i2o+ce6H/6BluujYR+kqX3GKH+dChPTQU19wjRPiGk=
53+
google.golang.org/grpc v1.79.1 h1:zGhSi45ODB9/p3VAawt9a+O/MULLl9dpizzNNpq7flY=
54+
google.golang.org/grpc v1.79.1/go.mod h1:KmT0Kjez+0dde/v2j9vzwoAScgEPx/Bw1CYChhHLrHQ=
55+
google.golang.org/protobuf v1.36.10 h1:AYd7cD/uASjIL6Q9LiTjz8JLcrh/88q5UObnmY3aOOE=
56+
google.golang.org/protobuf v1.36.10/go.mod h1:HTf+CrKn2C3g5S8VImy6tdcUvCska2kB7j23XfzDpco=
1957
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
2058
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

grpc_interceptor/.rr.yaml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
version: "3"
2+
server:
3+
command: "php grpc-worker.php"
4+
grpc:
5+
listen: "tcp://127.0.0.1:9001"
6+
proto:
7+
- "proto/helloworld.proto"
8+
interceptors:
9+
- "sample-grpc-interceptor"

grpc_interceptor/README.md

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# gRPC Interceptor Sample
2+
3+
This sample demonstrates a custom RoadRunner gRPC interceptor plugin.
4+
5+
The interceptor implementation is in `plugin.go` and exposes:
6+
7+
- `Name() string`
8+
- `UnaryServerInterceptor() grpc.UnaryServerInterceptor`
9+
10+
## Register the plugin in RR
11+
12+
When you build your custom RoadRunner binary, register this plugin in the RR container list (for example, in `container/plugins.go`):
13+
14+
```go
15+
import (
16+
grpcPlugin "github.com/roadrunner-server/grpc/v5"
17+
grpcInterceptor "github.com/roadrunner-server/samples/grpc_interceptor"
18+
)
19+
20+
func Plugins() []any {
21+
return []any{
22+
// ...
23+
&grpcInterceptor.Plugin{},
24+
&grpcPlugin.Plugin{},
25+
// ...
26+
}
27+
}
28+
```
29+
30+
## Configure interceptor chain
31+
32+
Use the plugin name returned by `Name()` under `grpc.interceptors`:
33+
34+
```yaml
35+
grpc:
36+
interceptors:
37+
- sample-grpc-interceptor
38+
```
39+
40+
The full runnable config example is in `.rr.yaml`.
41+
42+
## Interceptor order
43+
44+
RoadRunner applies configured interceptors in reverse order from `grpc.interceptors`.
45+
46+
Example:
47+
48+
```yaml
49+
grpc:
50+
interceptors: ["first", "second", "third"]
51+
```
52+
53+
Execution order will be: `third -> second -> first -> handler`.

grpc_interceptor/plugin.go

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
// Package interceptor demonstrates a custom RoadRunner gRPC interceptor plugin.
2+
package interceptor
3+
4+
import (
5+
"context"
6+
"time"
7+
8+
"go.uber.org/zap"
9+
"google.golang.org/grpc"
10+
"google.golang.org/grpc/status"
11+
)
12+
13+
const name = "sample-grpc-interceptor"
14+
15+
type Logger interface {
16+
NamedLogger(name string) *zap.Logger
17+
}
18+
19+
type Plugin struct {
20+
log *zap.Logger
21+
}
22+
23+
func (p *Plugin) Init(logger Logger) error {
24+
p.log = logger.NamedLogger(name)
25+
return nil
26+
}
27+
28+
func (p *Plugin) UnaryServerInterceptor() grpc.UnaryServerInterceptor {
29+
return func(ctx context.Context, req any, info *grpc.UnaryServerInfo, handler grpc.UnaryHandler) (any, error) {
30+
started := time.Now()
31+
32+
resp, err := handler(ctx, req)
33+
if err != nil {
34+
st, _ := status.FromError(err)
35+
p.log.Warn(
36+
"grpc request failed",
37+
zap.String("method", info.FullMethod),
38+
zap.String("status", st.Code().String()),
39+
zap.Int64("elapsed_ms", time.Since(started).Milliseconds()),
40+
zap.Error(err),
41+
)
42+
43+
return resp, err
44+
}
45+
46+
p.log.Info(
47+
"grpc request completed",
48+
zap.String("method", info.FullMethod),
49+
zap.Int64("elapsed_ms", time.Since(started).Milliseconds()),
50+
)
51+
52+
return resp, nil
53+
}
54+
}
55+
56+
func (p *Plugin) Name() string {
57+
return name
58+
}

0 commit comments

Comments
 (0)