Skip to content

Commit f21ffbc

Browse files
authored
Merge pull request #41 from protoconf/avivl/issue-38
Avivl/issue-38
2 parents 0e210d2 + 58df4e6 commit f21ffbc

File tree

3 files changed

+50
-39
lines changed

3 files changed

+50
-39
lines changed

go.mod

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ module github.com/protoconf/client-go
33
go 1.22.4
44

55
require (
6+
github.com/avast/retry-go v3.0.0+incompatible
67
github.com/fsnotify/fsnotify v1.7.0
78
github.com/protoconf/protoconf v0.1.7
89
github.com/stretchr/testify v1.9.0

go.sum

Lines changed: 4 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,32 @@
1-
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
1+
github.com/avast/retry-go v3.0.0+incompatible h1:4SOWQ7Qs+oroOTQOYnAHqelpCO0biHSxpiH9JdtuBj0=
2+
github.com/avast/retry-go v3.0.0+incompatible/go.mod h1:XtSnn+n/sHqQIpZ10K1qAevBhOOCWBLXXy3hyiqqBrY=
23
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
34
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
45
github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA=
56
github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM=
6-
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
7-
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
8-
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
97
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
108
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
11-
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
12-
github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
13-
github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
9+
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
10+
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
1411
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
1512
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
1613
github.com/protoconf/protoconf v0.1.7 h1:qa2tM5ltSonYEQFdJNClB4TH5PB1jnCqp2/GLD4RDRE=
1714
github.com/protoconf/protoconf v0.1.7/go.mod h1:WczqUWu57i4z8okvOVb+4+p94h3RkJW59nmuXZq810U=
18-
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
19-
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
20-
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
21-
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
22-
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
23-
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
24-
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
2515
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
2616
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
27-
golang.org/x/net v0.23.0 h1:7EYJ93RZ9vYSZAIb2x3lnuvqO5zneoD6IvWjuhfxjTs=
28-
golang.org/x/net v0.23.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
2917
golang.org/x/net v0.26.0 h1:soB7SVo0PWrY4vPW/+ay0jKDNScG2X9wFeYlXIvJsOQ=
3018
golang.org/x/net v0.26.0/go.mod h1:5YKkiSynbBIh3p6iOc/vibscux0x38BZDkn8sCUPxHE=
31-
golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4=
32-
golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
3319
golang.org/x/sys v0.21.0 h1:rF+pYz3DAGSQAxAu1CbC7catZg4ebC4UIeIhKxBZvws=
3420
golang.org/x/sys v0.21.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
35-
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
36-
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
3721
golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
3822
golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
39-
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
4023
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1 h1:KpwkzHKEF7B9Zxg18WzOa7djJ+Ha5DzthMyZYQfEn2A=
4124
google.golang.org/genproto v0.0.0-20230410155749-daa745c078e1/go.mod h1:nKE/iIaLqn2bQwXBg8f1g2Ylh6r5MN5CmZvuzZCgsCU=
42-
google.golang.org/grpc v1.56.3 h1:8I4C0Yq1EjstUzUJzpcRVbuYA2mODtEmpWiQoN/b2nc=
43-
google.golang.org/grpc v1.56.3/go.mod h1:I9bI3vqKfayGqPUAwGdOSu7kt6oIJLixfffKrpXqQ9s=
44-
google.golang.org/grpc v1.64.0 h1:KH3VH9y/MgNQg1dE7b3XfVK0GsPSIzJwdF617gUSbvY=
45-
google.golang.org/grpc v1.64.0/go.mod h1:oxjF8E3FBnjp+/gVFYdWacaLDx9na1aqy9oovLpxQYg=
46-
google.golang.org/grpc v1.64.1 h1:LKtvyfbX3UGVPFcGqJ9ItpVWW6oN/2XqTxfAnwRRXiA=
47-
google.golang.org/grpc v1.64.1/go.mod h1:hiQF4LFZelK2WKaP6W0L92zGHtiQdZxk8CrSdvyjeP0=
4825
google.golang.org/grpc v1.65.0 h1:bs/cUb4lp1G5iImFFd3u5ixQzweKizoZJAwBNLR42lc=
4926
google.golang.org/grpc v1.65.0/go.mod h1:WgYC2ypjlB0EiQi6wdKixMqukr6lBc0Vo+oOgjrM5ZQ=
50-
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
51-
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
52-
google.golang.org/protobuf v1.33.0 h1:uNO2rsAINq/JlFpSdYEKIZ0uKD/R9cpdv0T+yoGwGmI=
53-
google.golang.org/protobuf v1.33.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
5427
google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg=
5528
google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw=
5629
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
5730
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
58-
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
5931
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
6032
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

protoconfloader.go

Lines changed: 45 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,9 @@ import (
99
"os"
1010
"path/filepath"
1111
"sync"
12+
"time"
1213

14+
"github.com/avast/retry-go"
1315
pc "github.com/protoconf/protoconf/agent/api/proto/v1"
1416
"google.golang.org/grpc"
1517
"google.golang.org/grpc/credentials/insecure"
@@ -21,6 +23,8 @@ import (
2123

2224
const (
2325
AgentDefaultAddress = ":4300"
26+
RetryAttempts = 3
27+
RetryDelay = 500 * time.Millisecond
2428
)
2529

2630
type Configuration struct {
@@ -223,33 +227,67 @@ func (c *Configuration) loadConfig() error {
223227
return nil
224228
}
225229

226-
// listenToChanges is a method of the Configuration struct that establishes a connection to a server using gRPC and subscribes to receive configuration updates.
230+
// listenToChanges establishes a connection to the Protoconf agent and listens for configuration changes.
231+
// It uses a retry mechanism to handle connection failures and reconnects automatically.
232+
//
233+
// Parameters:
234+
// - path: A string representing the configuration path to subscribe to.
235+
// - ctx: A context.Context for managing the lifecycle of the listening operation.
236+
//
237+
// Returns:
238+
// - error: An error if the connection and listening process fails after all retry attempts,
239+
// or nil if successful.
240+
func (c *Configuration) listenToChanges(path string, ctx context.Context) error {
241+
configs := []retry.Option{
242+
retry.Attempts(uint(RetryAttempts)),
243+
retry.Delay(RetryDelay),
244+
retry.OnRetry(func(n uint, err error) {
245+
c.logger.Error("Retry request ", slog.Int("#", int(n+1)), slog.Any("error", err))
246+
}),
247+
retry.Delay(time.Second),
248+
}
249+
err := retry.Do(func() error {
250+
err := c.connectAndListen(path, ctx)
251+
if err != nil {
252+
c.logger.Error("Error in agent communication, reconnecting",
253+
slog.String("path", path),
254+
slog.Any("error", err))
255+
256+
}
257+
return err
258+
},
259+
configs...,
260+
)
261+
return err
262+
}
263+
264+
// connectAndListen establishes a connection to a server using gRPC and subscribes to receive configuration updates.
227265
// It takes a path string and a context.Context as parameters.
228-
// It first gets the hostname to use for the connection by calling the getHostname method.
266+
//
267+
// The function first gets the hostname to use for the connection by calling the getHostname method.
229268
// Then it dials the server using the obtained address and insecure transport credentials.
230269
// If there is an error while dialing, it logs the error and returns it.
270+
//
231271
// It creates a new ProtoconfServiceClient using the connection.
232272
// It creates a new context with cancellation capability using the provided context.
233273
// It subscribes for configuration updates by calling the SubscribeForConfig method of the ProtoconfServiceClient.
234274
// If there is an error while subscribing, it logs the error and returns it.
275+
//
235276
// It starts a goroutine to handle the received configuration updates by calling the handleConfigUpdates method.
236277
// Finally, it returns nil.
237-
func (c *Configuration) listenToChanges(path string, ctx context.Context) error {
278+
func (c *Configuration) connectAndListen(path string, ctx context.Context) error {
238279
psc := c.agentStub
239280
if psc == nil {
240281
address := c.getHostname()
241-
242-
conn, err := grpc.Dial(address, grpc.WithTransportCredentials(insecure.NewCredentials()))
282+
conn, err := grpc.NewClient(address, grpc.WithTransportCredentials(insecure.NewCredentials()))
243283
if err != nil {
244284
c.logger.Error("Error connecting to server ", slog.String("address", address), slog.Any("error", err))
245285
return err
246286
}
247-
248287
psc = pc.NewProtoconfServiceClient(conn)
249288
}
250289
stream, err := psc.SubscribeForConfig(ctx, &pc.ConfigSubscriptionRequest{Path: path})
251290
if err != nil {
252-
c.logger.Error("Error subscribing for config", slog.String("path", path), slog.Any("error", err))
253291
return err
254292
}
255293
go c.handleConfigUpdates(stream, path)

0 commit comments

Comments
 (0)