Tariffs: retry download with backoff (#8833)
This commit is contained in:
parent
ed7c7c8147
commit
7c92e0daa5
9 changed files with 76 additions and 32 deletions
|
|
@ -6,6 +6,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/tariff/awattar"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
|
|
@ -55,11 +56,15 @@ func NewAwattarFromConfig(other map[string]interface{}) (api.Tariff, error) {
|
|||
|
||||
func (t *Awattar) run(done chan error) {
|
||||
var once sync.Once
|
||||
bo := newBackoff()
|
||||
client := request.NewHelper(t.log)
|
||||
|
||||
for ; true; <-time.Tick(time.Hour) {
|
||||
var res awattar.Prices
|
||||
if err := client.GetJSON(t.uri, &res); err != nil {
|
||||
|
||||
if err := backoff.Retry(func() error {
|
||||
return client.GetJSON(t.uri, &res)
|
||||
}, bo); err != nil {
|
||||
once.Do(func() { done <- err })
|
||||
|
||||
t.log.ERROR.Println(err)
|
||||
|
|
@ -92,7 +97,7 @@ func (t *Awattar) Rates() (api.Rates, error) {
|
|||
return slices.Clone(t.data), outdatedError(t.updated, time.Hour)
|
||||
}
|
||||
|
||||
// Type returns the tariff type
|
||||
// Type implements the api.Tariff interface
|
||||
func (t *Awattar) Type() api.TariffType {
|
||||
return api.TariffTypePriceDynamic
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/request"
|
||||
|
|
@ -78,11 +79,15 @@ func NewElectricityMapsFromConfig(other map[string]interface{}) (api.Tariff, err
|
|||
|
||||
func (t *ElectricityMaps) run(done chan error) {
|
||||
var once sync.Once
|
||||
bo := newBackoff()
|
||||
uri := fmt.Sprintf("%s/carbon-intensity/forecast?zone=%s", t.uri, t.zone)
|
||||
|
||||
for ; true; <-time.Tick(time.Hour) {
|
||||
var res CarbonIntensity
|
||||
if err := t.GetJSON(uri, &res); err != nil {
|
||||
|
||||
if err := backoff.Retry(func() error {
|
||||
return t.GetJSON(uri, &res)
|
||||
}, bo); err != nil {
|
||||
if res.Error != "" {
|
||||
err = errors.New(res.Error)
|
||||
}
|
||||
|
|
@ -119,7 +124,7 @@ func (t *ElectricityMaps) Rates() (api.Rates, error) {
|
|||
return res, outdatedError(t.updated, time.Hour)
|
||||
}
|
||||
|
||||
// Type returns the tariff type
|
||||
// Type implements the api.Tariff interface
|
||||
func (t *ElectricityMaps) Type() api.TariffType {
|
||||
return api.TariffTypeCo2
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/tariff/elering"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
|
|
@ -60,6 +61,7 @@ func NewEleringFromConfig(other map[string]interface{}) (api.Tariff, error) {
|
|||
func (t *Elering) run(done chan error) {
|
||||
var once sync.Once
|
||||
client := request.NewHelper(t.log)
|
||||
bo := newBackoff()
|
||||
|
||||
for ; true; <-time.Tick(time.Hour) {
|
||||
var res elering.NpsPrice
|
||||
|
|
@ -69,7 +71,9 @@ func (t *Elering) run(done chan error) {
|
|||
url.QueryEscape(ts.Format(time.RFC3339)),
|
||||
url.QueryEscape(ts.Add(48*time.Hour).Format(time.RFC3339)))
|
||||
|
||||
if err := client.GetJSON(uri, &res); err != nil {
|
||||
if err := backoff.Retry(func() error {
|
||||
return client.GetJSON(uri, &res)
|
||||
}, bo); err != nil {
|
||||
once.Do(func() { done <- err })
|
||||
|
||||
t.log.ERROR.Println(err)
|
||||
|
|
@ -106,7 +110,7 @@ func (t *Elering) Rates() (api.Rates, error) {
|
|||
return slices.Clone(t.data), outdatedError(t.updated, time.Hour)
|
||||
}
|
||||
|
||||
// Type returns the tariff type
|
||||
// Type implements the api.Tariff interface
|
||||
func (t *Elering) Type() api.TariffType {
|
||||
return api.TariffTypePriceDynamic
|
||||
}
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/tariff/energinet"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
|
|
@ -59,6 +60,7 @@ func NewEnerginetFromConfig(other map[string]interface{}) (api.Tariff, error) {
|
|||
func (t *Energinet) run(done chan error) {
|
||||
var once sync.Once
|
||||
client := request.NewHelper(t.log)
|
||||
bo := newBackoff()
|
||||
|
||||
for ; true; <-time.Tick(time.Hour) {
|
||||
var res energinet.Prices
|
||||
|
|
@ -69,7 +71,9 @@ func (t *Energinet) run(done chan error) {
|
|||
ts.Add(24*time.Hour).Format(time.RFC3339),
|
||||
t.region)
|
||||
|
||||
if err := client.GetJSON(uri, &res); err != nil {
|
||||
if err := backoff.Retry(func() error {
|
||||
return client.GetJSON(uri, &res)
|
||||
}, bo); err != nil {
|
||||
once.Do(func() { done <- err })
|
||||
|
||||
t.log.ERROR.Println(err)
|
||||
|
|
@ -103,7 +107,7 @@ func (t *Energinet) Rates() (api.Rates, error) {
|
|||
return slices.Clone(t.data), outdatedError(t.updated, time.Hour)
|
||||
}
|
||||
|
||||
// Type returns the tariff type
|
||||
// Type implements the api.Tariff interface
|
||||
func (t *Energinet) Type() api.TariffType {
|
||||
return api.TariffTypePriceDynamic
|
||||
}
|
||||
|
|
|
|||
|
|
@ -129,7 +129,7 @@ func (t *Fixed) Rates() (api.Rates, error) {
|
|||
return res, nil
|
||||
}
|
||||
|
||||
// Type returns the tariff type
|
||||
// Type implements the api.Tariff interface
|
||||
func (t *Fixed) Type() api.TariffType {
|
||||
if t.dynamic {
|
||||
return api.TariffTypePriceDynamic
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
"github.com/evcc-io/evcc/util/request"
|
||||
|
|
@ -13,7 +14,6 @@ import (
|
|||
)
|
||||
|
||||
type GrünStromIndex struct {
|
||||
*request.Helper
|
||||
log *util.Logger
|
||||
mux sync.Mutex
|
||||
zip string
|
||||
|
|
@ -76,9 +76,8 @@ func NewGrünStromIndexFromConfig(other map[string]interface{}) (api.Tariff, err
|
|||
log := util.NewLogger("gsi").Redact(cc.Zip)
|
||||
|
||||
t := &GrünStromIndex{
|
||||
log: log,
|
||||
Helper: request.NewHelper(log),
|
||||
zip: cc.Zip,
|
||||
log: log,
|
||||
zip: cc.Zip,
|
||||
}
|
||||
|
||||
done := make(chan error)
|
||||
|
|
@ -90,11 +89,17 @@ func NewGrünStromIndexFromConfig(other map[string]interface{}) (api.Tariff, err
|
|||
|
||||
func (t *GrünStromIndex) run(done chan error) {
|
||||
var once sync.Once
|
||||
client := request.NewHelper(t.log)
|
||||
bo := newBackoff()
|
||||
uri := fmt.Sprintf("https://api.corrently.io/v2.0/gsi/prediction?zip=%s", t.zip)
|
||||
|
||||
for ; true; <-time.Tick(time.Hour) {
|
||||
var res gsiForecast
|
||||
err := t.GetJSON(uri, &res)
|
||||
|
||||
err := backoff.Retry(func() error {
|
||||
return client.GetJSON(uri, &res)
|
||||
}, bo)
|
||||
|
||||
if err == nil && res.Err {
|
||||
if s, ok := res.Message.(string); ok {
|
||||
err = errors.New(s)
|
||||
|
|
@ -135,7 +140,7 @@ func (t *GrünStromIndex) Rates() (api.Rates, error) {
|
|||
return slices.Clone(t.data), outdatedError(t.updated, time.Hour)
|
||||
}
|
||||
|
||||
// Type returns the tariff type
|
||||
// Type implements the api.Tariff interface
|
||||
func (t *GrünStromIndex) Type() api.TariffType {
|
||||
return api.TariffTypeCo2
|
||||
}
|
||||
|
|
|
|||
14
tariff/helper.go
Normal file
14
tariff/helper.go
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
package tariff
|
||||
|
||||
import (
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
)
|
||||
|
||||
func newBackoff() backoff.BackOff {
|
||||
bo := backoff.NewExponentialBackOff()
|
||||
bo.InitialInterval = 5 * time.Second
|
||||
bo.MaxElapsedTime = time.Minute
|
||||
return bo
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/tariff/octopus"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
|
|
@ -60,10 +61,14 @@ func NewOctopusFromConfig(other map[string]interface{}) (api.Tariff, error) {
|
|||
func (t *Octopus) run(done chan error) {
|
||||
var once sync.Once
|
||||
client := request.NewHelper(t.log)
|
||||
bo := newBackoff()
|
||||
|
||||
for ; true; <-time.Tick(time.Hour) {
|
||||
var res octopus.UnitRates
|
||||
if err := client.GetJSON(t.uri, &res); err != nil {
|
||||
|
||||
if err := backoff.Retry(func() error {
|
||||
return client.GetJSON(t.uri, &res)
|
||||
}, bo); err != nil {
|
||||
once.Do(func() { done <- err })
|
||||
|
||||
t.log.ERROR.Println(err)
|
||||
|
|
@ -103,7 +108,7 @@ func (t *Octopus) Rates() (api.Rates, error) {
|
|||
return slices.Clone(t.data), outdatedError(t.updated, time.Hour)
|
||||
}
|
||||
|
||||
// Type returns the tariff type
|
||||
// Type implements the api.Tariff interface
|
||||
func (t *Octopus) Type() api.TariffType {
|
||||
return api.TariffTypePriceDynamic
|
||||
}
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/cenkalti/backoff/v4"
|
||||
"github.com/evcc-io/evcc/api"
|
||||
"github.com/evcc-io/evcc/meter/tibber"
|
||||
"github.com/evcc-io/evcc/util"
|
||||
|
|
@ -73,27 +74,28 @@ func NewTibberFromConfig(other map[string]interface{}) (api.Tariff, error) {
|
|||
|
||||
func (t *Tibber) run(done chan error) {
|
||||
var once sync.Once
|
||||
|
||||
var res struct {
|
||||
Viewer struct {
|
||||
Home struct {
|
||||
ID string
|
||||
TimeZone string
|
||||
CurrentSubscription tibber.Subscription
|
||||
} `graphql:"home(id: $id)"`
|
||||
}
|
||||
}
|
||||
bo := newBackoff()
|
||||
|
||||
v := map[string]interface{}{
|
||||
"id": graphql.ID(t.homeID),
|
||||
}
|
||||
|
||||
for ; true; <-time.Tick(time.Hour) {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), request.Timeout)
|
||||
err := t.client.Query(ctx, &res, v)
|
||||
cancel()
|
||||
var res struct {
|
||||
Viewer struct {
|
||||
Home struct {
|
||||
ID string
|
||||
TimeZone string
|
||||
CurrentSubscription tibber.Subscription
|
||||
} `graphql:"home(id: $id)"`
|
||||
}
|
||||
}
|
||||
|
||||
if err != nil {
|
||||
if err := backoff.Retry(func() error {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), request.Timeout)
|
||||
defer cancel()
|
||||
return t.client.Query(ctx, &res, v)
|
||||
}, bo); err != nil {
|
||||
once.Do(func() { done <- err })
|
||||
|
||||
t.log.ERROR.Println(err)
|
||||
|
|
@ -137,7 +139,7 @@ func (t *Tibber) Rates() (api.Rates, error) {
|
|||
return slices.Clone(t.data), outdatedError(t.updated, time.Hour)
|
||||
}
|
||||
|
||||
// Type returns the tariff type
|
||||
// Type implements the api.Tariff interface
|
||||
func (t *Tibber) Type() api.TariffType {
|
||||
return api.TariffTypePriceDynamic
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue