Skip to content

Commit 3ec30dc

Browse files
committed
pass tests + proper linting
1 parent 56da741 commit 3ec30dc

File tree

6 files changed

+445
-70
lines changed

6 files changed

+445
-70
lines changed

go.work.sum

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -195,6 +195,7 @@ cloud.google.com/go/compute v1.34.0 h1:+k/kmViu4TEi97NGaxAATYtpYBviOWJySPZ+ekA95
195195
cloud.google.com/go/compute v1.34.0/go.mod h1:zWZwtLwZQyonEvIQBuIa0WvraMYK69J5eDCOw9VZU4g=
196196
cloud.google.com/go/compute v1.37.0 h1:XxtZlXYkZXub3LNaLu90TTemcFqIU1yZ4E4q9VlR39A=
197197
cloud.google.com/go/compute v1.37.0/go.mod h1:AsK4VqrSyXBo4SMbRtfAO1VfaMjUEjEwv1UB/AwVp5Q=
198+
cloud.google.com/go/compute v1.38.0 h1:MilCLYQW2m7Dku8hRIIKo4r0oKastlD74sSu16riYKs=
198199
cloud.google.com/go/compute/metadata v0.3.0/go.mod h1:zFmK7XCadkQkj6TtorcaGlCW1hT1fIilQDwofLpJ20k=
199200
cloud.google.com/go/compute/metadata v0.5.2/go.mod h1:C66sj2AluDcIqakBq/M8lw8/ybHgOZqin2obFxa/E5k=
200201
cloud.google.com/go/compute/metadata v0.6.0/go.mod h1:FjyFAW1MW0C203CEOMDTu3Dk1FlqW3Rga40jzHL4hfg=
@@ -1144,13 +1145,15 @@ go.opentelemetry.io/contrib/instrumentation/net/http/httptrace/otelhttptrace v0.
11441145
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.49.0/go.mod h1:p8pYQP+m5XfbZm9fxtSKAbM6oIllS7s2AfxrChvc7iw=
11451146
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.54.0/go.mod h1:L7UH0GbB0p47T4Rri3uHjbpCFYrVrwc1I25QhNPiGK8=
11461147
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.58.0/go.mod h1:umTcuxiv1n/s/S6/c2AT/g2CQ7u5C59sHDNmfSwgz7Q=
1148+
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.61.0/go.mod h1:UHB22Z8QsdRDrnAtX4PntOl36ajSxcdUMt1sF7Y6E7Q=
11471149
go.opentelemetry.io/otel v1.22.0/go.mod h1:eoV4iAi3Ea8LkAEI9+GFT44O6T/D0GWAVFyZVCC6pMI=
11481150
go.opentelemetry.io/otel v1.24.0/go.mod h1:W7b9Ozg4nkF5tWI5zsXkaKKDjdVjpD4oAt9Qi/MArHo=
11491151
go.opentelemetry.io/otel v1.29.0/go.mod h1:N/WtXPs1CNCUEx+Agz5uouwCba+i+bJGFicT8SR4NP8=
11501152
go.opentelemetry.io/otel v1.31.0/go.mod h1:O0C14Yl9FgkjqcCZAsE053C13OaddMYr/hz6clDkEJE=
11511153
go.opentelemetry.io/otel v1.32.0/go.mod h1:00DCVSB0RQcnzlwyTfqtxSm+DRr9hpYrHjNGiBHVQIg=
11521154
go.opentelemetry.io/otel v1.34.0/go.mod h1:OWFPOQ+h4G8xpyjgqo4SxJYdDQ/qmRH+wivy7zzx9oI=
11531155
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
1156+
go.opentelemetry.io/otel v1.36.0/go.mod h1:/TcFMXYjyRNh8khOAO9ybYkqaDBb/70aVwkNML4pP8E=
11541157
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0 h1:IeMeyr1aBvBiPVYihXIaeIZba6b8E1bYp7lbdxK8CQg=
11551158
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.19.0/go.mod h1:oVdCUtjq9MK9BlS7TtucsQwUcXcymNiEDjgDD2jMtZU=
11561159
go.opentelemetry.io/otel/exporters/stdout/stdoutmetric v1.29.0 h1:WDdP9acbMYjbKIyJUhTvtzj601sVJOqgWdUxSdR/Ysc=
@@ -1163,6 +1166,7 @@ go.opentelemetry.io/otel/metric v1.32.0/go.mod h1:jH7CIbbK6SH2V2wE16W05BHCtIDzau
11631166
go.opentelemetry.io/otel/metric v1.33.0/go.mod h1:L9+Fyctbp6HFTddIxClbQkjtubW6O9QS3Ann/M82u6M=
11641167
go.opentelemetry.io/otel/metric v1.34.0/go.mod h1:CEDrp0fy2D0MvkXE+dPV7cMi8tWZwX3dmaIhwPOaqHE=
11651168
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
1169+
go.opentelemetry.io/otel/metric v1.36.0/go.mod h1:zC7Ks+yeyJt4xig9DEw9kuUFe5C3zLbVjV2PzT6qzbs=
11661170
go.opentelemetry.io/otel/sdk v1.22.0/go.mod h1:iu7luyVGYovrRpe2fmj3CVKouQNdTOkxtLzPvPz1DOc=
11671171
go.opentelemetry.io/otel/sdk v1.29.0/go.mod h1:pM8Dx5WKnvxLCb+8lG1PRNIDxu9g9b9g59Qr7hfAAok=
11681172
go.opentelemetry.io/otel/sdk v1.32.0/go.mod h1:LqgegDBjKMmb2GC6/PrTnteJG39I8/vJCAP9LlJXEjU=
@@ -1175,6 +1179,7 @@ go.opentelemetry.io/otel/trace v1.31.0/go.mod h1:TXZkRk7SM2ZQLtR6eoAWQFIHPvzQ06F
11751179
go.opentelemetry.io/otel/trace v1.32.0/go.mod h1:+i4rkvCraA+tG6AzwloGaCtkx53Fa+L+V8e9a7YvhT8=
11761180
go.opentelemetry.io/otel/trace v1.34.0/go.mod h1:Svm7lSjQD7kG7KJ/MUHPVXSDGz2OX4h0M2jHBhmSfRE=
11771181
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
1182+
go.opentelemetry.io/otel/trace v1.36.0/go.mod h1:gQ+OnDZzrybY4k4seLzPAWNwVBBVlF2szhehOBB/tGA=
11781183
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
11791184
go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE=
11801185
go.uber.org/atomic v1.11.0/go.mod h1:LUxbIzbOniOlMKjJjyPfpl4v+PKK2cNJn91OQbhoJI0=
@@ -1260,7 +1265,6 @@ golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
12601265
golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k=
12611266
golang.org/x/net v0.35.0/go.mod h1:EglIi67kWsHKlRzzVMUD93VMSWGFOMSZgxFjparz1Qk=
12621267
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
1263-
golang.org/x/net v0.40.0/go.mod h1:y0hY0exeL2Pku80/zKK7tpntoX23cqL3Oa6njdgRtds=
12641268
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
12651269
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
12661270
golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -1286,6 +1290,7 @@ golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
12861290
golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
12871291
golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
12881292
golang.org/x/sync v0.14.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
1293+
golang.org/x/sync v0.15.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA=
12891294
golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
12901295
golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
12911296
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -1335,7 +1340,6 @@ golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
13351340
golang.org/x/text v0.19.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
13361341
golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
13371342
golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU=
1338-
golang.org/x/text v0.25.0/go.mod h1:WEdwpYrmk1qmdHvhkSTNPm3app7v4rsT8F2UD6+VHIA=
13391343
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
13401344
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
13411345
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1489,6 +1493,7 @@ google.golang.org/genproto/googleapis/bytestream v0.0.0-20250512202823-5a2f75b73
14891493
google.golang.org/genproto/googleapis/bytestream v0.0.0-20250512202823-5a2f75b736a9/go.mod h1:h6yxum/C2qRb4txaZRLDHK8RyS0H/o2oEDeKY4onY/Y=
14901494
google.golang.org/genproto/googleapis/bytestream v0.0.0-20250603155806-513f23925822 h1:zWFRixYR5QlotL+Uv3YfsPRENIrQFXiGs+iwqel6fOQ=
14911495
google.golang.org/genproto/googleapis/bytestream v0.0.0-20250603155806-513f23925822/go.mod h1:h6yxum/C2qRb4txaZRLDHK8RyS0H/o2oEDeKY4onY/Y=
1496+
google.golang.org/genproto/googleapis/bytestream v0.0.0-20250728155136-f173205681a0/go.mod h1:h6yxum/C2qRb4txaZRLDHK8RyS0H/o2oEDeKY4onY/Y=
14921497
google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
14931498
google.golang.org/genproto/googleapis/rpc v0.0.0-20240429193739-8cf5692501f6/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY=
14941499
google.golang.org/genproto/googleapis/rpc v0.0.0-20240814211410-ddb44dafa142/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU=

pkg/gofr/factory.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ func New() *App {
5757
port = defaultGRPCPort
5858
}
5959

60-
app.grpcServer = newGRPCServer(app.container, port, app.Config)
60+
app.grpcServer, _ = newGRPCServer(app.container, port, app.Config)
6161

6262
app.subscriptionManager = newSubscriptionManager(app.container)
6363

pkg/gofr/grpc.go

Lines changed: 95 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package gofr
33
import (
44
"context"
55
"errors"
6+
"fmt"
67
"net"
78
"reflect"
89
"strconv"
@@ -27,6 +28,12 @@ type grpcServer struct {
2728
config config.Config
2829
}
2930

31+
var (
32+
ErrNonAddressable = errors.New("cannot inject container as it is not addressable or is nil")
33+
ErrInvalidPort = errors.New("invalid port number")
34+
ErrFailedCreateServer = errors.New("failed to create gRPC server")
35+
)
36+
3037
// AddGRPCServerOptions allows users to add custom gRPC server options such as TLS configuration,
3138
// timeouts, interceptors, and other server-specific settings in a single call.
3239
//
@@ -42,6 +49,12 @@ type grpcServer struct {
4249
// This function accepts a variadic list of gRPC server options (grpc.ServerOption) and appends them
4350
// to the server's configuration. It allows fine-tuning of the gRPC server's behavior during its initialization.
4451
func (a *App) AddGRPCServerOptions(grpcOpts ...grpc.ServerOption) {
52+
if len(grpcOpts) == 0 {
53+
a.container.Logger.Debug("no gRPC server options provided")
54+
return
55+
}
56+
57+
a.container.Logger.Debugf("adding %d gRPC server options", len(grpcOpts))
4558
a.grpcServer.options = append(a.grpcServer.options, grpcOpts...)
4659
}
4760

@@ -55,14 +68,32 @@ func (a *App) AddGRPCServerOptions(grpcOpts ...grpc.ServerOption) {
5568
// }
5669
// app.AddGRPCUnaryInterceptors(loggingInterceptor)
5770
func (a *App) AddGRPCUnaryInterceptors(interceptors ...grpc.UnaryServerInterceptor) {
71+
if len(interceptors) == 0 {
72+
a.container.Logger.Debug("no unary interceptors provided")
73+
return
74+
}
75+
76+
a.container.Logger.Debugf("adding %d valid unary interceptors", len(interceptors))
5877
a.grpcServer.interceptors = append(a.grpcServer.interceptors, interceptors...)
5978
}
6079

6180
func (a *App) AddGRPCServerStreamInterceptors(interceptors ...grpc.StreamServerInterceptor) {
81+
if len(interceptors) == 0 {
82+
a.container.Logger.Debug("no stream interceptors provided")
83+
return
84+
}
85+
86+
a.container.Logger.Debugf("adding %d stream interceptors", len(interceptors))
6287
a.grpcServer.streamInterceptors = append(a.grpcServer.streamInterceptors, interceptors...)
6388
}
6489

65-
func newGRPCServer(c *container.Container, port int, cfg config.Config) *grpcServer {
90+
func newGRPCServer(c *container.Container, port int, cfg config.Config) (*grpcServer, error) {
91+
if port <= 0 || port > 65535 {
92+
return nil, fmt.Errorf("%w: %d", ErrInvalidPort, port)
93+
}
94+
95+
registerGRPCMetrics(c)
96+
6697
middleware := make([]grpc.UnaryServerInterceptor, 0)
6798
middleware = append(middleware,
6899
grpc_recovery.UnaryServerInterceptor(),
@@ -78,41 +109,78 @@ func newGRPCServer(c *container.Container, port int, cfg config.Config) *grpcSer
78109
interceptors: middleware,
79110
streamInterceptors: streamMiddleware,
80111
config: cfg,
81-
}
112+
}, nil
82113
}
83114

84-
func (g *grpcServer) createServer() {
115+
// registerGRPCMetrics registers essential gRPC metrics.
116+
func registerGRPCMetrics(c *container.Container) {
117+
c.Metrics().NewGauge("grpc_server_status", "gRPC server status (1=running, 0=stopped)")
118+
c.Metrics().NewCounter("grpc_server_errors_total", "Total gRPC server errors")
119+
c.Metrics().NewCounter("grpc_services_registered_total", "Total gRPC services registered")
120+
}
121+
122+
func (g *grpcServer) createServer() error {
85123
interceptorOption := grpc.UnaryInterceptor(grpc_middleware.ChainUnaryServer(g.interceptors...))
86124
streamOpt := grpc.StreamInterceptor(grpc_middleware.ChainStreamServer(g.streamInterceptors...))
87125
g.options = append(g.options, interceptorOption, streamOpt)
88126

89127
g.server = grpc.NewServer(g.options...)
128+
if g.server == nil {
129+
return ErrFailedCreateServer
130+
}
90131

91132
enabled := strings.ToLower(g.config.GetOrDefault("GRPC_ENABLE_REFLECTION", "false"))
92-
if enabled != defaultReflection {
133+
if enabled == defaultTelemetry {
93134
reflection.Register(g.server)
94135
}
136+
137+
return nil
95138
}
96139

97140
func (g *grpcServer) Run(c *container.Container) {
98141
if g.server == nil {
99-
g.createServer()
142+
if err := g.createServer(); err != nil {
143+
c.Logger.Fatalf("failed to create gRPC server: %v", err)
144+
c.Metrics().IncrementCounter(context.Background(), "grpc_server_errors_total")
145+
146+
return
147+
}
148+
}
149+
150+
if !isPortAvailable(g.port) {
151+
c.Logger.Fatalf("gRPC port %d is blocked or unreachable", g.port)
152+
c.Metrics().IncrementCounter(context.Background(), "grpc_server_errors_total")
153+
c.Metrics().SetGauge("grpc_server_status", 0)
154+
155+
return
100156
}
101157

102158
addr := ":" + strconv.Itoa(g.port)
103159

104160
c.Logger.Infof("starting gRPC server at %s", addr)
105161

106-
listener, err := net.Listen("tcp", addr)
162+
listener, err := (&net.ListenConfig{}).Listen(context.Background(), "tcp", addr)
107163
if err != nil {
108164
c.Logger.Errorf("error in starting gRPC server at %s: %s", addr, err)
165+
c.Metrics().IncrementCounter(context.Background(), "grpc_server_errors_total")
166+
c.Metrics().SetGauge("grpc_server_status", 0)
167+
109168
return
110169
}
111170

171+
c.Metrics().SetGauge("grpc_server_status", 1)
172+
c.Logger.Infof("gRPC server started successfully on %s", addr)
173+
112174
if err := g.server.Serve(listener); err != nil {
113175
c.Logger.Errorf("error in starting gRPC server at %s: %s", addr, err)
176+
c.Metrics().IncrementCounter(context.Background(), "grpc_server_errors_total")
177+
c.Metrics().SetGauge("grpc_server_status", 0)
178+
114179
return
115180
}
181+
182+
c.Logger.Infof("gRPC server stopped on %s", addr)
183+
c.Metrics().SetGauge("grpc_server_status", 0)
116184
}
117185

118186
func (g *grpcServer) Shutdown(ctx context.Context) error {
@@ -129,29 +197,27 @@ func (g *grpcServer) Shutdown(ctx context.Context) error {
129197
})
130198
}
131199

132-
var (
133-
errNonAddressable = errors.New("cannot inject container as it is not addressable or is fail")
134-
)
135-
136200
// RegisterService adds a gRPC service to the GoFr application.
137201
func (a *App) RegisterService(desc *grpc.ServiceDesc, impl any) {
138-
if !a.grpcRegistered && !isPortAvailable(a.grpcServer.port) {
139-
a.container.Logger.Fatalf("gRPC port %d is blocked or unreachable", a.grpcServer.port)
140-
}
141-
142202
if !a.grpcRegistered {
143-
a.grpcServer.createServer()
203+
if err := a.grpcServer.createServer(); err != nil {
204+
a.container.Logger.Errorf("failed to create gRPC server for service %s: %v", desc.ServiceName, err)
205+
return
206+
}
144207
}
145208

146-
a.container.Logger.Infof("registering gRPC Server: %s", desc.ServiceName)
209+
a.container.Logger.Infof("registering gRPC Service: %s", desc.ServiceName)
147210
a.grpcServer.server.RegisterService(desc, impl)
148211

212+
a.container.Metrics().IncrementCounter(context.Background(), "grpc_services_registered_total")
213+
149214
err := injectContainer(impl, a.container)
150215
if err != nil {
151-
return
216+
a.container.Logger.Fatalf("failed to inject container into gRPC service %s: %v", desc.ServiceName, err)
152217
}
153218

154219
a.grpcRegistered = true
220+
a.container.Logger.Infof("successfully registered gRPC service: %s", desc.ServiceName)
155221
}
156222

157223
func injectContainer(impl any, c *container.Container) error {
@@ -177,8 +243,8 @@ func injectContainer(impl any, c *container.Container) error {
177243

178244
if f.Type == reflect.TypeOf(c) {
179245
if !v.CanSet() {
180-
c.Logger.Error(errNonAddressable)
181-
return errNonAddressable
246+
c.Logger.Error(ErrNonAddressable)
247+
return ErrNonAddressable
182248
}
183249

184250
v.Set(reflect.ValueOf(c))
@@ -189,8 +255,8 @@ func injectContainer(impl any, c *container.Container) error {
189255

190256
if f.Type == reflect.TypeOf(*c) {
191257
if !v.CanSet() {
192-
c.Logger.Error(errNonAddressable)
193-
return errNonAddressable
258+
c.Logger.Error(ErrNonAddressable)
259+
return ErrNonAddressable
194260
}
195261

196262
v.Set(reflect.ValueOf(*c))
@@ -202,3 +268,11 @@ func injectContainer(impl any, c *container.Container) error {
202268

203269
return nil
204270
}
271+
272+
func (g *grpcServer) addServerOptions(opts ...grpc.ServerOption) {
273+
g.options = append(g.options, opts...)
274+
}
275+
276+
func (g *grpcServer) addUnaryInterceptors(interceptors ...grpc.UnaryServerInterceptor) {
277+
g.interceptors = append(g.interceptors, interceptors...)
278+
}

0 commit comments

Comments
 (0)