Skip to content

Commit 392cbc4

Browse files
Improvement: gRPC server
1 parent d0bb612 commit 392cbc4

File tree

7 files changed

+180
-6
lines changed

7 files changed

+180
-6
lines changed

go.mod

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,19 +2,24 @@ module github.com/dipdup-net/indexer-sdk
22

33
go 1.20
44

5+
56
require (
67
github.com/dipdup-net/go-lib v0.3.0
78
github.com/ethereum/go-ethereum v1.12.0
89
github.com/go-testfixtures/testfixtures/v3 v3.9.0
10+
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0-rc.0
11+
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.5
912
github.com/iancoleman/strcase v0.3.0
1013
github.com/json-iterator/go v1.1.12
1114
github.com/lib/pq v1.10.9
1215
github.com/pkg/errors v0.9.1
16+
github.com/prometheus/client_golang v1.16.0
1317
github.com/robfig/cron/v3 v3.0.1
1418
github.com/rs/zerolog v1.30.0
1519
github.com/spf13/cobra v1.7.0
1620
github.com/stretchr/testify v1.8.4
1721
github.com/uptrace/bun v1.1.14
22+
golang.org/x/time v0.3.0
1823
google.golang.org/grpc v1.57.0
1924
google.golang.org/protobuf v1.31.0
2025
gopkg.in/yaml.v3 v3.0.1
@@ -27,8 +32,10 @@ require (
2732
github.com/ClickHouse/clickhouse-go/v2 v2.13.0 // indirect
2833
github.com/Microsoft/go-winio v0.6.1 // indirect
2934
github.com/andybalholm/brotli v1.0.5 // indirect
35+
github.com/beorn7/perks v1.0.1 // indirect
3036
github.com/btcsuite/btcd/btcec/v2 v2.3.2 // indirect
3137
github.com/cenkalti/backoff/v4 v4.2.1 // indirect
38+
github.com/cespare/xxhash/v2 v2.2.0 // indirect
3239
github.com/containerd/containerd v1.7.3 // indirect
3340
github.com/cpuguy83/dockercfg v0.3.1 // indirect
3441
github.com/davecgh/go-spew v1.1.1 // indirect
@@ -62,6 +69,7 @@ require (
6269
github.com/mattn/go-colorable v0.1.13 // indirect
6370
github.com/mattn/go-isatty v0.0.19 // indirect
6471
github.com/mattn/go-sqlite3 v1.14.17 // indirect
72+
github.com/matttproud/golang_protobuf_extensions v1.0.4 // indirect
6573
github.com/moby/patternmatcher v0.5.0 // indirect
6674
github.com/moby/sys/sequential v0.5.0 // indirect
6775
github.com/moby/term v0.5.0 // indirect
@@ -75,6 +83,9 @@ require (
7583
github.com/paulmach/orb v0.10.0 // indirect
7684
github.com/pierrec/lz4/v4 v4.1.18 // indirect
7785
github.com/pmezard/go-difflib v1.0.0 // indirect
86+
github.com/prometheus/client_model v0.3.0 // indirect
87+
github.com/prometheus/common v0.42.0 // indirect
88+
github.com/prometheus/procfs v0.10.1 // indirect
7889
github.com/segmentio/asm v1.2.0 // indirect
7990
github.com/shopspring/decimal v1.3.1 // indirect
8091
github.com/sirupsen/logrus v1.9.3 // indirect

go.sum

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,15 @@ github.com/VictoriaMetrics/fastcache v1.6.0 h1:C/3Oi3EiBCqufydp1neRZkqcwmEiuRT9c
1717
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
1818
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
1919
github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
20+
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
2021
github.com/btcsuite/btcd/btcec/v2 v2.3.2 h1:5n0X6hX0Zk+6omWcihdYvdAlGf2DfasC0GMf7DClJ3U=
2122
github.com/btcsuite/btcd/btcec/v2 v2.3.2/go.mod h1:zYzJ8etWJQIv1Ogk7OzpWjowwOdXY1W/17j2MW85J04=
2223
github.com/btcsuite/btcd/chaincfg/chainhash v1.0.1 h1:q0rUy8C/TYNBQS1+CGKw68tLOFYSNEs0TFnxxnS9+4U=
2324
github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM=
2425
github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE=
2526
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
2627
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
28+
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
2729
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
2830
github.com/cockroachdb/errors v1.9.1 h1:yFVvsI0VxmRShfawbt/laCIDy/mtTqqnvoNgiy5bEV8=
2931
github.com/cockroachdb/logtags v0.0.0-20230118201751-21c54148d20b h1:r6VH0faHjZeQy818SGhaone5OnYfxFR/+AzdY3sf5aE=
@@ -97,6 +99,7 @@ github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfb
9799
github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc=
98100
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
99101
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
102+
github.com/golang/protobuf v1.3.5/go.mod h1:6O5/vntMXwX2lRkT1hjjk0nAC1IDOTvTlVgjlRvqsdk=
100103
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
101104
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
102105
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
@@ -121,6 +124,10 @@ github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
121124
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
122125
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I=
123126
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
127+
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0-rc.0 h1:mdLirNAJBxnGgyB6pjZLcs6ue/6eZGBui6gXspfq4ks=
128+
github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus v1.0.0-rc.0/go.mod h1:kdXbOySqcQeTxiqglW7aahTmWZy3Pgi6SYL36yvKeyA=
129+
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.5 h1:3IZOAnD058zZllQTZNBioTlrzrBG/IjpiZ133IEtusM=
130+
github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.0.0-rc.5/go.mod h1:xbKERva94Pw2cPen0s79J3uXmGzbbpDYFBFDlZ4mV/w=
124131
github.com/holiman/uint256 v1.2.3 h1:K8UWO1HUJpRMXBxbmaY1Y8IAMZC/RsKB+ArEnnK4l5o=
125132
github.com/holiman/uint256 v1.2.3/go.mod h1:SC8Ryt4n+UBbPbIBKaG9zbbDlp4jOru9xFZmPzLUTxw=
126133
github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU=
@@ -175,6 +182,7 @@ github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/Qd
175182
github.com/mattn/go-sqlite3 v1.14.17 h1:mCRHCLDUBXgpKAqIKsaAaAsrAlbkeomtRFKXh2L6YIM=
176183
github.com/mattn/go-sqlite3 v1.14.17/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
177184
github.com/matttproud/golang_protobuf_extensions v1.0.4 h1:mmDVorXM7PCGKw94cs5zkfA9PSy5pEvNWRP0ET0TIVo=
185+
github.com/matttproud/golang_protobuf_extensions v1.0.4/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
178186
github.com/moby/patternmatcher v0.5.0 h1:YCZgJOeULcxLw1Q+sVR636pmS7sPEn1Qo2iAN6M7DBo=
179187
github.com/moby/patternmatcher v0.5.0/go.mod h1:hDPoyOpDY7OrrMDLaYoY3hf52gNCR/YOUYxkhApJIxc=
180188
github.com/moby/sys/sequential v0.5.0 h1:OPvI35Lzn9K04PBbCLW0g4LcFAJgHsvXsRyewg5lXtc=
@@ -218,10 +226,14 @@ github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
218226
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
219227
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
220228
github.com/prometheus/client_golang v1.16.0 h1:yk/hx9hDbrGHovbci4BY+pRMfSuuat626eFsHb7tmT8=
229+
github.com/prometheus/client_golang v1.16.0/go.mod h1:Zsulrv/L9oM40tJ7T815tM89lFEugiJ9HzIqaAx4LKc=
221230
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
222231
github.com/prometheus/client_model v0.3.0 h1:UBgGFHqYdG/TPFD1B1ogZywDqEkwp3fBMvqdiQ7Xew4=
232+
github.com/prometheus/client_model v0.3.0/go.mod h1:LDGWKZIo7rky3hgvBe+caln+Dr3dPggB5dvjtD7w9+w=
223233
github.com/prometheus/common v0.42.0 h1:EKsfXEYo4JpWMHH5cg+KOUWeuJSov1Id8zGR8eeI1YM=
234+
github.com/prometheus/common v0.42.0/go.mod h1:xBwqVerjNdUDjgODMpudtOMwlOwf2SaTr1yjz4b7Zbc=
224235
github.com/prometheus/procfs v0.10.1 h1:kYK1Va/YMlutzCGazswoHKo//tZVlFpKYh+PymziUAg=
236+
github.com/prometheus/procfs v0.10.1/go.mod h1:nwNm2aOCAYw8uTR/9bWRREkZFxAUcWzPHWJq+XBB/FM=
225237
github.com/robfig/cron/v3 v3.0.1 h1:WdRxkvbJztn8LMz/QEvLN5sBU+xKpSqwwUO1Pjr4qDs=
226238
github.com/robfig/cron/v3 v3.0.1/go.mod h1:eQICP3HwyT7UooqI/z+Ov+PtYAWygg1TEWWzGIFLtro=
227239
github.com/rogpeppe/go-internal v1.10.0 h1:TMyTOH3F/DB16zRVcYyreMH6GnZZrwQVAoYjRBZyWFQ=
@@ -328,6 +340,7 @@ golang.org/x/net v0.14.0/go.mod h1:PpSgVXXLK0OxS0F31C1/tv6XNguvCrnXIDrFMspZIUI=
328340
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
329341
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
330342
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
343+
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
331344
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
332345
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
333346
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -369,7 +382,8 @@ golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
369382
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
370383
golang.org/x/text v0.12.0 h1:k+n5B8goJNdU7hSvEtMUz3d1Q6D/XW4COJSJR6fN0mc=
371384
golang.org/x/text v0.12.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
372-
golang.org/x/time v0.0.0-20220922220347-f3bd1da661af h1:Yx9k8YCG3dvF87UAn2tu2HQLf2dt/eR1bXxpLMWeH+Y=
385+
golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4=
386+
golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
373387
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
374388
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
375389
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=

pkg/modules/grpc/client.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
gogrpc "google.golang.org/grpc"
1414
"google.golang.org/grpc/backoff"
1515
"google.golang.org/grpc/connectivity"
16+
"google.golang.org/grpc/encoding/gzip"
1617
"google.golang.org/grpc/keepalive"
1718
)
1819

@@ -65,6 +66,7 @@ func (client *Client) Connect(ctx context.Context, opts ...ConnectOption) error
6566
},
6667
))
6768
dialOpts = append(dialOpts, gogrpc.WithUserAgent(connectOpts.userAgent))
69+
dialOpts = append(dialOpts, grpc.WithDefaultCallOptions(grpc.UseCompressor(gzip.Name)))
6870

6971
if connectOpts.wait {
7072
dialOpts = append(dialOpts, gogrpc.WithBlock())

pkg/modules/grpc/config.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,8 @@ package grpc
22

33
// ServerConfig - config for server
44
type ServerConfig struct {
5-
Bind string `yaml:"bind" validate:"required,hostname_port"`
5+
Bind string `yaml:"bind" validate:"required,hostname_port"`
6+
Log bool `yaml:"log" validate:"omitempty"`
7+
Metrics bool `yaml:"metrics" validate:"omitempty"`
8+
RPS int `yaml:"rps" validate:"omitempty,min=1"`
69
}

pkg/modules/grpc/limiter.go

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package grpc
2+
3+
import (
4+
"context"
5+
"time"
6+
7+
"github.com/pkg/errors"
8+
"golang.org/x/time/rate"
9+
)
10+
11+
type simpleLimiter struct {
12+
limiter *rate.Limiter
13+
}
14+
15+
func newSimpleLimiter(rps int) *simpleLimiter {
16+
return &simpleLimiter{limiter: rate.NewLimiter(rate.Every(time.Second/time.Duration(rps)), rps)}
17+
}
18+
19+
// Limit tells wether or not to allow a certain request
20+
// depending on the underlying limiter decision.
21+
func (l *simpleLimiter) Limit(_ context.Context) error {
22+
if !l.limiter.Allow() {
23+
return errors.New("rate limit exceeded")
24+
}
25+
26+
return nil
27+
}

pkg/modules/grpc/log.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
package grpc
2+
3+
import (
4+
"context"
5+
"fmt"
6+
7+
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging"
8+
"github.com/rs/zerolog"
9+
"github.com/rs/zerolog/log"
10+
)
11+
12+
func logCalls() logging.Logger {
13+
return logging.LoggerFunc(func(ctx context.Context, lvl logging.Level, msg string, fields ...any) {
14+
l := log.With().Ctx(ctx).Str("module", "grpc").Logger()
15+
16+
event := new(zerolog.Event)
17+
switch lvl {
18+
case logging.LevelDebug:
19+
event = l.Debug()
20+
case logging.LevelInfo:
21+
event = l.Info()
22+
case logging.LevelWarn:
23+
event = l.Warn()
24+
case logging.LevelError:
25+
event = l.Error()
26+
default:
27+
panic(fmt.Sprintf("unknown level %v", lvl))
28+
}
29+
30+
event.Fields(fields).Msg(msg)
31+
})
32+
}

pkg/modules/grpc/server.go

Lines changed: 89 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,24 +4,33 @@ import (
44
"context"
55
"io"
66
"net"
7+
"net/http"
78
"sync"
89
"sync/atomic"
910
"time"
1011

1112
"github.com/pkg/errors"
13+
"github.com/prometheus/client_golang/prometheus"
14+
"github.com/prometheus/client_golang/prometheus/promhttp"
1215
"github.com/rs/zerolog/log"
1316

1417
"github.com/dipdup-net/indexer-sdk/pkg/modules/grpc/pb"
18+
grpcprom "github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus"
19+
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/logging"
20+
"github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors/ratelimit"
1521
"google.golang.org/grpc"
1622
gogrpc "google.golang.org/grpc"
23+
_ "google.golang.org/grpc/encoding/gzip" // Install the gzip compressor
1724
"google.golang.org/grpc/keepalive"
1825
)
1926

2027
// Server - basic server structure which implemented module interface and handle stats endpoints.
2128
type Server struct {
2229
bind string
2330

24-
server *gogrpc.Server
31+
server *gogrpc.Server
32+
metricsServer *http.Server
33+
srvMetrics *grpcprom.ServerMetrics
2534

2635
wg *sync.WaitGroup
2736
}
@@ -35,7 +44,8 @@ func NewServer(cfg *ServerConfig) (*Server, error) {
3544
bind: cfg.Bind,
3645
wg: new(sync.WaitGroup),
3746
}
38-
module.server = gogrpc.NewServer(
47+
48+
opts := []gogrpc.ServerOption{
3949
gogrpc.KeepaliveParams(
4050
keepalive.ServerParameters{
4151
Time: 20 * time.Second,
@@ -47,10 +57,61 @@ func NewServer(cfg *ServerConfig) (*Server, error) {
4757
MinTime: 10 * time.Second,
4858
PermitWithoutStream: true,
4959
},
50-
))
60+
),
61+
}
62+
63+
streamInterceptors := make([]gogrpc.StreamServerInterceptor, 0)
64+
unaryInterceptors := make([]gogrpc.UnaryServerInterceptor, 0)
65+
66+
if cfg.Log {
67+
streamInterceptors = append(streamInterceptors, logging.StreamServerInterceptor(logCalls()))
68+
unaryInterceptors = append(unaryInterceptors, logging.UnaryServerInterceptor(logCalls()))
69+
70+
}
71+
72+
if cfg.Metrics {
73+
module.metricsServer, module.srvMetrics = newMetricsServer("127.0.0.1:6789")
74+
streamInterceptors = append(streamInterceptors, module.srvMetrics.StreamServerInterceptor())
75+
unaryInterceptors = append(unaryInterceptors, module.srvMetrics.UnaryServerInterceptor())
76+
}
77+
78+
if cfg.RPS > 0 {
79+
limiter := newSimpleLimiter(cfg.RPS)
80+
streamInterceptors = append(streamInterceptors, ratelimit.StreamServerInterceptor(limiter))
81+
unaryInterceptors = append(unaryInterceptors, ratelimit.UnaryServerInterceptor(limiter))
82+
}
83+
84+
if len(streamInterceptors) > 0 {
85+
opts = append(opts,
86+
gogrpc.ChainStreamInterceptor(streamInterceptors...),
87+
)
88+
}
89+
if len(unaryInterceptors) > 0 {
90+
opts = append(opts,
91+
gogrpc.ChainUnaryInterceptor(unaryInterceptors...),
92+
)
93+
}
94+
95+
module.server = gogrpc.NewServer(opts...)
5196
return module, nil
5297
}
5398

99+
func newMetricsServer(httpAddr string) (*http.Server, *grpcprom.ServerMetrics) {
100+
httpSrv := &http.Server{Addr: httpAddr}
101+
m := http.NewServeMux()
102+
103+
srvMetrics := grpcprom.NewServerMetrics(
104+
grpcprom.WithServerHandlingTimeHistogram(
105+
grpcprom.WithHistogramBuckets([]float64{0.001, 0.01, 0.1, 0.3, 0.6, 1, 3, 6, 9, 20, 30, 60, 90, 120}),
106+
),
107+
)
108+
reg := prometheus.NewRegistry()
109+
reg.MustRegister(srvMetrics)
110+
m.Handle("/metrics", promhttp.HandlerFor(reg, promhttp.HandlerOpts{}))
111+
httpSrv.Handler = m
112+
return httpSrv, srvMetrics
113+
}
114+
54115
// Name -
55116
func (*Server) Name() string {
56117
return "grpc_server"
@@ -60,6 +121,9 @@ func (*Server) Name() string {
60121
func (module *Server) Start(ctx context.Context) {
61122
module.wg.Add(1)
62123
go module.grpc(ctx)
124+
125+
module.wg.Add(1)
126+
go module.startMetricsServer(ctx)
63127
}
64128

65129
func (module *Server) grpc(ctx context.Context) {
@@ -77,9 +141,30 @@ func (module *Server) grpc(ctx context.Context) {
77141
}
78142
}
79143

144+
func (module *Server) startMetricsServer(ctx context.Context) {
145+
defer module.wg.Done()
146+
147+
if module.metricsServer == nil {
148+
return
149+
}
150+
151+
if err := module.metricsServer.ListenAndServe(); err != nil && err != http.ErrServerClosed {
152+
log.Err(err).Msg("failed to serve metrics")
153+
return
154+
}
155+
log.Info().Msg("metrics server shutdown")
156+
}
157+
80158
// Close - closes server module
81159
func (module *Server) Close() error {
82-
module.server.Stop()
160+
if module.metricsServer != nil {
161+
if err := module.metricsServer.Shutdown(context.Background()); err != nil {
162+
return err
163+
}
164+
}
165+
module.server.GracefulStop()
166+
167+
module.wg.Wait()
83168
return nil
84169
}
85170

0 commit comments

Comments
 (0)