Skip to content

Commit 7c92e0d

Browse files
authored
Tariffs: retry download with backoff (evcc-io#8833)
1 parent ed7c7c8 commit 7c92e0d

9 files changed

+76
-32
lines changed

tariff/awattar.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"sync"
77
"time"
88

9+
"github.com/cenkalti/backoff/v4"
910
"github.com/evcc-io/evcc/api"
1011
"github.com/evcc-io/evcc/tariff/awattar"
1112
"github.com/evcc-io/evcc/util"
@@ -55,11 +56,15 @@ func NewAwattarFromConfig(other map[string]interface{}) (api.Tariff, error) {
5556

5657
func (t *Awattar) run(done chan error) {
5758
var once sync.Once
59+
bo := newBackoff()
5860
client := request.NewHelper(t.log)
5961

6062
for ; true; <-time.Tick(time.Hour) {
6163
var res awattar.Prices
62-
if err := client.GetJSON(t.uri, &res); err != nil {
64+
65+
if err := backoff.Retry(func() error {
66+
return client.GetJSON(t.uri, &res)
67+
}, bo); err != nil {
6368
once.Do(func() { done <- err })
6469

6570
t.log.ERROR.Println(err)
@@ -92,7 +97,7 @@ func (t *Awattar) Rates() (api.Rates, error) {
9297
return slices.Clone(t.data), outdatedError(t.updated, time.Hour)
9398
}
9499

95-
// Type returns the tariff type
100+
// Type implements the api.Tariff interface
96101
func (t *Awattar) Type() api.TariffType {
97102
return api.TariffTypePriceDynamic
98103
}

tariff/electricitymaps.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"sync"
88
"time"
99

10+
"github.com/cenkalti/backoff/v4"
1011
"github.com/evcc-io/evcc/api"
1112
"github.com/evcc-io/evcc/util"
1213
"github.com/evcc-io/evcc/util/request"
@@ -78,11 +79,15 @@ func NewElectricityMapsFromConfig(other map[string]interface{}) (api.Tariff, err
7879

7980
func (t *ElectricityMaps) run(done chan error) {
8081
var once sync.Once
82+
bo := newBackoff()
8183
uri := fmt.Sprintf("%s/carbon-intensity/forecast?zone=%s", t.uri, t.zone)
8284

8385
for ; true; <-time.Tick(time.Hour) {
8486
var res CarbonIntensity
85-
if err := t.GetJSON(uri, &res); err != nil {
87+
88+
if err := backoff.Retry(func() error {
89+
return t.GetJSON(uri, &res)
90+
}, bo); err != nil {
8691
if res.Error != "" {
8792
err = errors.New(res.Error)
8893
}
@@ -119,7 +124,7 @@ func (t *ElectricityMaps) Rates() (api.Rates, error) {
119124
return res, outdatedError(t.updated, time.Hour)
120125
}
121126

122-
// Type returns the tariff type
127+
// Type implements the api.Tariff interface
123128
func (t *ElectricityMaps) Type() api.TariffType {
124129
return api.TariffTypeCo2
125130
}

tariff/elering.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ import (
88
"sync"
99
"time"
1010

11+
"github.com/cenkalti/backoff/v4"
1112
"github.com/evcc-io/evcc/api"
1213
"github.com/evcc-io/evcc/tariff/elering"
1314
"github.com/evcc-io/evcc/util"
@@ -60,6 +61,7 @@ func NewEleringFromConfig(other map[string]interface{}) (api.Tariff, error) {
6061
func (t *Elering) run(done chan error) {
6162
var once sync.Once
6263
client := request.NewHelper(t.log)
64+
bo := newBackoff()
6365

6466
for ; true; <-time.Tick(time.Hour) {
6567
var res elering.NpsPrice
@@ -69,7 +71,9 @@ func (t *Elering) run(done chan error) {
6971
url.QueryEscape(ts.Format(time.RFC3339)),
7072
url.QueryEscape(ts.Add(48*time.Hour).Format(time.RFC3339)))
7173

72-
if err := client.GetJSON(uri, &res); err != nil {
74+
if err := backoff.Retry(func() error {
75+
return client.GetJSON(uri, &res)
76+
}, bo); err != nil {
7377
once.Do(func() { done <- err })
7478

7579
t.log.ERROR.Println(err)
@@ -106,7 +110,7 @@ func (t *Elering) Rates() (api.Rates, error) {
106110
return slices.Clone(t.data), outdatedError(t.updated, time.Hour)
107111
}
108112

109-
// Type returns the tariff type
113+
// Type implements the api.Tariff interface
110114
func (t *Elering) Type() api.TariffType {
111115
return api.TariffTypePriceDynamic
112116
}

tariff/energinet.go

+6-2
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"sync"
88
"time"
99

10+
"github.com/cenkalti/backoff/v4"
1011
"github.com/evcc-io/evcc/api"
1112
"github.com/evcc-io/evcc/tariff/energinet"
1213
"github.com/evcc-io/evcc/util"
@@ -59,6 +60,7 @@ func NewEnerginetFromConfig(other map[string]interface{}) (api.Tariff, error) {
5960
func (t *Energinet) run(done chan error) {
6061
var once sync.Once
6162
client := request.NewHelper(t.log)
63+
bo := newBackoff()
6264

6365
for ; true; <-time.Tick(time.Hour) {
6466
var res energinet.Prices
@@ -69,7 +71,9 @@ func (t *Energinet) run(done chan error) {
6971
ts.Add(24*time.Hour).Format(time.RFC3339),
7072
t.region)
7173

72-
if err := client.GetJSON(uri, &res); err != nil {
74+
if err := backoff.Retry(func() error {
75+
return client.GetJSON(uri, &res)
76+
}, bo); err != nil {
7377
once.Do(func() { done <- err })
7478

7579
t.log.ERROR.Println(err)
@@ -103,7 +107,7 @@ func (t *Energinet) Rates() (api.Rates, error) {
103107
return slices.Clone(t.data), outdatedError(t.updated, time.Hour)
104108
}
105109

106-
// Type returns the tariff type
110+
// Type implements the api.Tariff interface
107111
func (t *Energinet) Type() api.TariffType {
108112
return api.TariffTypePriceDynamic
109113
}

tariff/fixed.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,7 @@ func (t *Fixed) Rates() (api.Rates, error) {
129129
return res, nil
130130
}
131131

132-
// Type returns the tariff type
132+
// Type implements the api.Tariff interface
133133
func (t *Fixed) Type() api.TariffType {
134134
if t.dynamic {
135135
return api.TariffTypePriceDynamic

tariff/gruenstromindex.go

+11-6
Original file line numberDiff line numberDiff line change
@@ -6,14 +6,14 @@ import (
66
"sync"
77
"time"
88

9+
"github.com/cenkalti/backoff/v4"
910
"github.com/evcc-io/evcc/api"
1011
"github.com/evcc-io/evcc/util"
1112
"github.com/evcc-io/evcc/util/request"
1213
"golang.org/x/exp/slices"
1314
)
1415

1516
type GrünStromIndex struct {
16-
*request.Helper
1717
log *util.Logger
1818
mux sync.Mutex
1919
zip string
@@ -76,9 +76,8 @@ func NewGrünStromIndexFromConfig(other map[string]interface{}) (api.Tariff, err
7676
log := util.NewLogger("gsi").Redact(cc.Zip)
7777

7878
t := &GrünStromIndex{
79-
log: log,
80-
Helper: request.NewHelper(log),
81-
zip: cc.Zip,
79+
log: log,
80+
zip: cc.Zip,
8281
}
8382

8483
done := make(chan error)
@@ -90,11 +89,17 @@ func NewGrünStromIndexFromConfig(other map[string]interface{}) (api.Tariff, err
9089

9190
func (t *GrünStromIndex) run(done chan error) {
9291
var once sync.Once
92+
client := request.NewHelper(t.log)
93+
bo := newBackoff()
9394
uri := fmt.Sprintf("https://api.corrently.io/v2.0/gsi/prediction?zip=%s", t.zip)
9495

9596
for ; true; <-time.Tick(time.Hour) {
9697
var res gsiForecast
97-
err := t.GetJSON(uri, &res)
98+
99+
err := backoff.Retry(func() error {
100+
return client.GetJSON(uri, &res)
101+
}, bo)
102+
98103
if err == nil && res.Err {
99104
if s, ok := res.Message.(string); ok {
100105
err = errors.New(s)
@@ -135,7 +140,7 @@ func (t *GrünStromIndex) Rates() (api.Rates, error) {
135140
return slices.Clone(t.data), outdatedError(t.updated, time.Hour)
136141
}
137142

138-
// Type returns the tariff type
143+
// Type implements the api.Tariff interface
139144
func (t *GrünStromIndex) Type() api.TariffType {
140145
return api.TariffTypeCo2
141146
}

tariff/helper.go

+14
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package tariff
2+
3+
import (
4+
"time"
5+
6+
"github.com/cenkalti/backoff/v4"
7+
)
8+
9+
func newBackoff() backoff.BackOff {
10+
bo := backoff.NewExponentialBackOff()
11+
bo.InitialInterval = 5 * time.Second
12+
bo.MaxElapsedTime = time.Minute
13+
return bo
14+
}

tariff/octopus.go

+7-2
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import (
55
"sync"
66
"time"
77

8+
"github.com/cenkalti/backoff/v4"
89
"github.com/evcc-io/evcc/api"
910
"github.com/evcc-io/evcc/tariff/octopus"
1011
"github.com/evcc-io/evcc/util"
@@ -60,10 +61,14 @@ func NewOctopusFromConfig(other map[string]interface{}) (api.Tariff, error) {
6061
func (t *Octopus) run(done chan error) {
6162
var once sync.Once
6263
client := request.NewHelper(t.log)
64+
bo := newBackoff()
6365

6466
for ; true; <-time.Tick(time.Hour) {
6567
var res octopus.UnitRates
66-
if err := client.GetJSON(t.uri, &res); err != nil {
68+
69+
if err := backoff.Retry(func() error {
70+
return client.GetJSON(t.uri, &res)
71+
}, bo); err != nil {
6772
once.Do(func() { done <- err })
6873

6974
t.log.ERROR.Println(err)
@@ -103,7 +108,7 @@ func (t *Octopus) Rates() (api.Rates, error) {
103108
return slices.Clone(t.data), outdatedError(t.updated, time.Hour)
104109
}
105110

106-
// Type returns the tariff type
111+
// Type implements the api.Tariff interface
107112
func (t *Octopus) Type() api.TariffType {
108113
return api.TariffTypePriceDynamic
109114
}

tariff/tibber.go

+17-15
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import (
66
"sync"
77
"time"
88

9+
"github.com/cenkalti/backoff/v4"
910
"github.com/evcc-io/evcc/api"
1011
"github.com/evcc-io/evcc/meter/tibber"
1112
"github.com/evcc-io/evcc/util"
@@ -73,27 +74,28 @@ func NewTibberFromConfig(other map[string]interface{}) (api.Tariff, error) {
7374

7475
func (t *Tibber) run(done chan error) {
7576
var once sync.Once
76-
77-
var res struct {
78-
Viewer struct {
79-
Home struct {
80-
ID string
81-
TimeZone string
82-
CurrentSubscription tibber.Subscription
83-
} `graphql:"home(id: $id)"`
84-
}
85-
}
77+
bo := newBackoff()
8678

8779
v := map[string]interface{}{
8880
"id": graphql.ID(t.homeID),
8981
}
9082

9183
for ; true; <-time.Tick(time.Hour) {
92-
ctx, cancel := context.WithTimeout(context.Background(), request.Timeout)
93-
err := t.client.Query(ctx, &res, v)
94-
cancel()
84+
var res struct {
85+
Viewer struct {
86+
Home struct {
87+
ID string
88+
TimeZone string
89+
CurrentSubscription tibber.Subscription
90+
} `graphql:"home(id: $id)"`
91+
}
92+
}
9593

96-
if err != nil {
94+
if err := backoff.Retry(func() error {
95+
ctx, cancel := context.WithTimeout(context.Background(), request.Timeout)
96+
defer cancel()
97+
return t.client.Query(ctx, &res, v)
98+
}, bo); err != nil {
9799
once.Do(func() { done <- err })
98100

99101
t.log.ERROR.Println(err)
@@ -137,7 +139,7 @@ func (t *Tibber) Rates() (api.Rates, error) {
137139
return slices.Clone(t.data), outdatedError(t.updated, time.Hour)
138140
}
139141

140-
// Type returns the tariff type
142+
// Type implements the api.Tariff interface
141143
func (t *Tibber) Type() api.TariffType {
142144
return api.TariffTypePriceDynamic
143145
}

0 commit comments

Comments
 (0)