DriveSomethingGreater: guard against losing data on error

This commit is contained in:
andig 2026-06-05 17:39:02 +02:00
parent 81bede7fe8
commit fe07fa7838
3 changed files with 8 additions and 27 deletions

View file

@ -60,7 +60,7 @@ func NewDriveSomethingGreaterFromConfig(other map[string]any) (api.Vehicle, erro
if err == nil {
v.fromVehicle(vehicle.Name(), 0)
v.Provider = eudataact.NewProvider(api, vehicle.Vin(), cc.Cache)
v.Provider = eudataact.NewProvider(log, api, vehicle.Vin(), cc.Cache)
}
return v, err

View file

@ -106,19 +106,3 @@ func TestMerge(t *testing.T) {
assert.Equal(t, "100", dst[FieldOdometer].Value, "older datapoint ignored")
assert.Equal(t, "200", dst[FieldRangeSecondary].Value, "new field added")
}
// TestResetDelay verifies the cache reset is scheduled for when the portal is
// expected to deliver the dataset following the one just read.
func TestResetDelay(t *testing.T) {
now := time.Date(2026, 5, 31, 12, 0, 0, 0, time.UTC)
// fresh dataset: reset one interval + latency later
assert.Equal(t, portalInterval+portalLatency, resetDelay(now, now))
// dataset already 5 min old: reset interval + latency after its timestamp
assert.Equal(t, portalInterval+portalLatency-5*time.Minute, resetDelay(now.Add(-5*time.Minute), now))
// next dataset already due: never reset sooner than the latency margin
assert.Equal(t, portalLatency, resetDelay(now.Add(-portalInterval), now))
assert.Equal(t, portalLatency, resetDelay(now.Add(-time.Hour), now))
}

View file

@ -10,11 +10,9 @@ import (
)
const (
// portalInterval is the cadence at which the portal delivers a new dataset
portalInterval = 15 * time.Minute
// portalLatency is the margin added to a dataset's timestamp before the
// following dataset is expected to be available for download
portalLatency = 30 * time.Second
portalLatency = time.Minute
)
// Provider implements the vehicle api on top of the EU Data Act dataset.
@ -32,7 +30,7 @@ type Provider struct {
}
// NewProvider creates a vehicle api provider
func NewProvider(api *API, vin string, cache time.Duration) *Provider {
func NewProvider(log *util.Logger, api *API, vin string, cache time.Duration) *Provider {
v := &Provider{}
s := sharedStore(api)
@ -40,10 +38,9 @@ func NewProvider(api *API, vin string, cache time.Duration) *Provider {
cached = util.ResettableCached(func() (map[string]point, error) {
ts, err := s.update(vin)
if err != nil {
return nil, err
}
if !ts.IsZero() {
time.AfterFunc(resetDelay(ts, time.Now()), cached.Reset)
log.ERROR.Println(err)
} else if !ts.IsZero() {
time.AfterFunc(resetDelay(ts, cache), cached.Reset)
}
return s.snapshot(vin), nil
}, cache)
@ -56,8 +53,8 @@ func NewProvider(api *API, vin string, cache time.Duration) *Provider {
// resetDelay returns the delay until the dataset following the one delivered at
// ts is expected to be available. It never returns less than portalLatency so a
// late or repeated dataset does not cause immediate re-polling.
func resetDelay(ts, now time.Time) time.Duration {
if d := ts.Add(portalInterval + portalLatency).Sub(now); d > portalLatency {
func resetDelay(ts time.Time, cache time.Duration) time.Duration {
if d := time.Until(ts.Add(cache + portalLatency)); d > portalLatency {
return d
}
return portalLatency