Skip to content

Commit c6f6398

Browse files
authored
fix: next day market data fetch (#20)
1 parent 2880e29 commit c6f6398

2 files changed

Lines changed: 27 additions & 5 deletions

File tree

‎entsoe/api_client.go‎

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,12 @@ type DownloadOptions struct {
4949
// DownloadPublicationMarketData downloads and decodes publication market data for the current and next day if needed.
5050
// fetchNextDay indicates whether to also download data for the next day (e.g. when it is past 13:30).
5151
// cache is an optional XMLDocumentCache; when non-nil, cached entries are returned instead of fetching from the network.
52-
func DownloadPublicationMarketData(ctx context.Context, securityToken string, urlFormat string, location *time.Location, fetchNextDay bool, cache *XMLDocumentCache) (*PublicationMarketData, error) {
52+
//
53+
// The second return value reports whether the returned document already covers the next day.
54+
// It is false when fetchNextDay is true but ENTSO-E has not published tomorrow's prices yet,
55+
// which lets callers shorten their cache lifetime and retry soon instead of caching a
56+
// partial (today-only) document for the rest of the day.
57+
func DownloadPublicationMarketData(ctx context.Context, securityToken string, urlFormat string, location *time.Location, fetchNextDay bool, cache *XMLDocumentCache) (*PublicationMarketData, bool, error) {
5358

5459
now := time.Now().In(location)
5560
client := NewAPIClient()
@@ -74,7 +79,7 @@ func DownloadPublicationMarketData(ctx context.Context, securityToken string, ur
7479
var rawXML []byte
7580
marketDocument, rawXML, err = downloadWithTimeout(ctx, url, opts)
7681
if err != nil {
77-
return nil, err
82+
return nil, false, err
7883
}
7984
if cache != nil {
8085
cache.StoreDocumentWithRaw(todayKey, marketDocument, rawXML, CacheSourceDownload)
@@ -106,7 +111,7 @@ func DownloadPublicationMarketData(ctx context.Context, securityToken string, ur
106111
fmt.Printf("No market data published yet for %s: %v\n", tomorrowKey, err)
107112
marketDocumentNextDay = nil
108113
} else {
109-
return nil, err
114+
return nil, false, err
110115
}
111116
} else if cache != nil {
112117
cache.StoreDocumentWithRaw(tomorrowKey, marketDocumentNextDay, rawXMLNextDay, CacheSourceDownload)
@@ -118,7 +123,10 @@ func DownloadPublicationMarketData(ctx context.Context, securityToken string, ur
118123
marketDocument = mergePublicationMarketData(marketDocument, marketDocumentNextDay)
119124
}
120125

121-
return marketDocument, nil
126+
// The result is complete unless the caller asked for the next day and it is still missing.
127+
nextDayIncluded := !fetchNextDay || marketDocumentNextDay != nil
128+
129+
return marketDocument, nextDayIncluded, nil
122130
}
123131

124132
// requestTimeout bounds a single ENTSO-E API call. The Transparency Platform can be

‎scheduler/pricing.go‎

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,12 @@ import (
88
"github.com/devskill-org/ems/entsoe"
99
)
1010

11+
// marketDataRetryInterval is how long a partial (today-only) market data document
12+
// is cached when the next day's prices have not been published by ENTSO-E yet.
13+
// It is long enough to avoid hammering the Transparency Platform every minute,
14+
// and short enough to pick up the prices soon after they appear.
15+
const marketDataRetryInterval = 15 * time.Minute
16+
1117
// StoreMarketDataXML parses the given XML bytes and stores the resulting document
1218
// in the XML document cache under the given date key (YYYY-MM-DD format).
1319
func (s *MinerScheduler) StoreMarketDataXML(date string, xmlData []byte) error {
@@ -99,11 +105,19 @@ func (s *MinerScheduler) GetMarketData(ctx context.Context) (*entsoe.Publication
99105

100106
// Perform the network download WITHOUT holding the lock so other goroutines
101107
// (GetConfig, runStateCheck, etc.) are never blocked during I/O.
102-
newDoc, err := entsoe.DownloadPublicationMarketData(ctx, s.config.SecurityToken, s.config.URLFormat, location, fetchNextDay, s.xmlCache)
108+
newDoc, nextDayIncluded, err := entsoe.DownloadPublicationMarketData(ctx, s.config.SecurityToken, s.config.URLFormat, location, fetchNextDay, s.xmlCache)
103109
if err != nil {
104110
return nil, fmt.Errorf("failed to download PublicationMarketData: %w", err)
105111
}
106112

113+
// ENTSO-E has not published tomorrow's day-ahead prices yet. Caching this
114+
// partial (today-only) document until tomorrow 13:30 would suppress every
115+
// subsequent refresh for ~24h, so expire it quickly and retry instead.
116+
if !nextDayIncluded {
117+
nextExpiry = now.Add(marketDataRetryInterval)
118+
s.logger.Printf("Next-day prices not published yet, retrying at %s", nextExpiry.Format(time.RFC3339))
119+
}
120+
107121
// Re-acquire the write lock only to store the result.
108122
// Double-check: another goroutine may have already refreshed while we were
109123
// downloading; keep whichever copy is fresher.

0 commit comments

Comments
 (0)