From aaaa28a42084199fc7ee52d24c0632d9739daab7 Mon Sep 17 00:00:00 2001 From: andig Date: Sat, 8 Aug 2026 13:57:02 +0200 Subject: [PATCH] Solcast: keep forecast alive outside active hours (#32639) --- tariff/helper_test.go | 27 +++++++++++++++++++++++++++ tariff/solcast.go | 2 ++ 2 files changed, 29 insertions(+) diff --git a/tariff/helper_test.go b/tariff/helper_test.go index 93e7ddee3..06bf96af7 100644 --- a/tariff/helper_test.go +++ b/tariff/helper_test.go @@ -62,6 +62,33 @@ func TestMergeRatesAfter(t *testing.T) { } } +// TestMergeRatesAfterRefreshesTimestamp asserts that merging without new rates +// keeps the cached rates and un-expires the monitor - this is how solcast keeps +// its forecast alive while fetching is paused outside the from/to window. +func TestMergeRatesAfterRefreshesTimestamp(t *testing.T) { + clock := clock.NewMock() + clock.Set(now.BeginningOfDay()) + + rates := api.Rates{{ + Start: clock.Now().Add(time.Hour), + End: clock.Now().Add(2 * time.Hour), + Value: 1, + }} + + data := util.NewMonitor[api.Rates](time.Hour).WithClock(clock) + data.Set(rates) + + clock.Add(2 * time.Hour) + _, err := data.Get() + require.ErrorIs(t, err, api.ErrOutdated) + + mergeRatesAfter(data, nil, clock.Now().Add(-2*time.Hour)) + + res, err := data.Get() + require.NoError(t, err) + assert.Equal(t, rates, res) +} + type runner struct { res error } diff --git a/tariff/solcast.go b/tariff/solcast.go index 957885167..f6227a44f 100644 --- a/tariff/solcast.go +++ b/tariff/solcast.go @@ -82,6 +82,8 @@ func (t *Solcast) run(interval time.Duration, done chan error) { select { case <-t.data.Done(): if !t.fromTo.IsActive(time.Now().Hour()) { + // keep cached forecast alive while fetching is paused + mergeRatesAfter(t.data, nil, beginningOfDay()) continue } default: