Skip to content

Commit a9ec457

Browse files
authored
Tibber Pulse: use longer timeouts (#23584)
1 parent 15958df commit a9ec457

1 file changed

Lines changed: 27 additions & 30 deletions

File tree

meter/tibber-pulse.go

Lines changed: 27 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import (
99
"strings"
1010
"time"
1111

12+
"github.com/cenkalti/backoff/v4"
1213
"github.com/evcc-io/evcc/api"
1314
"github.com/evcc-io/evcc/meter/tibber"
1415
"github.com/evcc-io/evcc/util"
@@ -109,34 +110,32 @@ func NewTibberFromConfig(ctx context.Context, other map[string]interface{}) (api
109110
WithConnectionParams(map[string]any{
110111
"token": cc.Token,
111112
}).
112-
WithRetryTimeout(15 * time.Second). // Retry 15 seconds (3 tries), then exit to outer retry loop that has backoff
113-
WithRetryDelay(5 * time.Second).
113+
WithRetryTimeout(20 * time.Second). // 2 tries, then exit to outer retry loop that has backoff
114+
WithRetryDelay(10 * time.Second).
114115
WithWriteTimeout(request.Timeout).
115116
WithReadTimeout(90 * time.Second).
116117
WithLog(log.TRACE.Println).
117118
OnConnected(func() {
118-
log.INFO.Println("Tibber pulse: websocket connected")
119+
log.DEBUG.Println("websocket connected")
119120
}).
120121
OnDisconnected(func() {
121-
log.WARN.Println("Tibber pulse: websocket disconnected")
122+
log.WARN.Println("websocket disconnected")
122123
}).
123124
OnSubscriptionComplete(func(_ graphql.Subscription) {
124-
log.WARN.Println("Tibber pulse: websocket subscription completed by server")
125+
log.DEBUG.Println("websocket subscription completed by server")
125126
}).
126127
OnError(func(sc *graphql.SubscriptionClient, err error) error {
127-
// Don't let Hasura go graphql client reconnect when authorization fails
128+
// Don't let graphql client reconnect when authorization fails
128129
if sc.IsUnauthorized(err) {
129-
log.ERROR.Printf("Tibber pulse: Unauthorized: %v", err)
130130
return err
131131
}
132132
// Don't let Hasura go graphql client reconnect when too many initialisation requests
133133
// Reconnection will be attempted in the loop later
134134
if sc.IsTooManyInitialisationRequests(err) {
135-
log.ERROR.Printf("Tibber pulse: Too many initialisation requests: %v", err)
136135
return err
137136
}
138137

139-
log.ERROR.Printf("Tibber pulse: error occurred: %v", err)
138+
log.ERROR.Printf("error occurred: %v", err)
140139
return nil
141140
})
142141

@@ -162,7 +161,6 @@ func NewTibberFromConfig(ctx context.Context, other map[string]interface{}) (api
162161
}
163162
}()
164163

165-
reconnectCount := 0
166164
go func() {
167165
// The pulse sometimes declines valid(!) subscription requests, and asks the client to disconnect.
168166
// Therefore we need to restart the client when exiting gracefully upon server request
@@ -173,47 +171,46 @@ func NewTibberFromConfig(ctx context.Context, other map[string]interface{}) (api
173171
// 2. This loop, which is triggered server when Hasura exits on error or gracefully
174172
// 3. evcc itself restarts if the client exits with an error
175173

176-
// Exponential backoff parameters
177-
baseDelay := 5 * time.Second
178-
maxDelay := 5 * time.Hour
179-
delay := baseDelay
174+
var reconnectCount int
175+
176+
bo := backoff.NewExponentialBackOff(
177+
backoff.WithInitialInterval(30*time.Second),
178+
backoff.WithMaxInterval(10*time.Minute),
179+
backoff.WithMaxElapsedTime(0),
180+
)
180181

181182
for {
182183
reconnectCount++
183-
log.INFO.Printf("Tibber pulse: Hasura go graphql client connection attempt #%d", reconnectCount)
184+
log.DEBUG.Printf("graphql client connection attempt #%d", reconnectCount)
184185

185186
startTime := time.Now()
186187
err := client.Run()
187188
duration := time.Since(startTime).Round(time.Second)
189+
188190
if err != nil {
189-
log.ERROR.Printf("Tibber pulse: Hasura go graphql client exited with error at %s: %v", duration, err)
191+
log.ERROR.Printf("graphql client exited with error at %s: %v", duration, err)
190192
// Do not retry if unauthorized
191193
if client.IsUnauthorized(err) {
192-
log.ERROR.Println("Tibber pulse: Not retrying due to unauthorized error.")
194+
log.ERROR.Println("Not retrying due to unauthorized error.")
193195
return
194196
}
195-
// Exponential backoff: double the delay, up to maxDelay
196-
delay *= 2
197-
if delay > maxDelay {
198-
delay = maxDelay
199-
}
200197
} else {
201-
log.INFO.Printf("Tibber pulse: Hasura go graphql client exited gracefully at %s", duration)
202-
// Reset delay after successful connection
203-
delay = baseDelay
198+
log.DEBUG.Printf("graphql client exited gracefully at %s", duration)
199+
bo.Reset()
204200
}
205201

202+
delay := bo.NextBackOff()
203+
206204
select {
207205
case <-time.After(delay):
208-
log.INFO.Printf("Tibber pulse: Reconnection timer triggered after %s, attempting reconnect", delay)
206+
log.DEBUG.Printf("reconnecting after %v backoff delay", delay)
209207
case <-ctx.Done():
210-
log.INFO.Println("Tibber pulse: Context canceled, exit reconnection loop")
211208
return
212209
}
213210
}
214211
}()
215212

216-
log.INFO.Printf("!! User-Agent set to %s", getUserAgent())
213+
log.DEBUG.Printf("!! User-Agent set to %s", getUserAgent())
217214

218215
return t, nil
219216
}
@@ -227,7 +224,7 @@ func (t *Tibber) subscribe(client *graphql.SubscriptionClient, homeID string, lo
227224
"homeId": graphql.ID(homeID),
228225
}, func(data []byte, err error) error {
229226
if err != nil {
230-
log.ERROR.Printf("Tibber pulse: Error during subscription: %v", err)
227+
log.ERROR.Printf("Error during subscription: %v", err)
231228
return err
232229
}
233230

@@ -236,7 +233,7 @@ func (t *Tibber) subscribe(client *graphql.SubscriptionClient, homeID string, lo
236233
}
237234

238235
if err := json.Unmarshal(data, &res); err != nil {
239-
log.ERROR.Printf("Tibber pulse: Error unmarshaling data: %v", err)
236+
log.ERROR.Printf("Error unmarshaling data: %v", err)
240237
return err
241238
}
242239

0 commit comments

Comments
 (0)