Overview
After a deployment or Redis flush, the first request for each asset hits all three upstream sources simultaneously, adding 500–2000ms of latency and consuming rate-limited API quota. Cache warming on startup eliminates this cold-start penalty.
Behaviour
On startup, before the HTTP server binds:
- Read the configured list of watched assets from
config.watchedAssets (or .env)
- Fetch prices for all assets in parallel (
Promise.allSettled)
- Populate Redis cache with the results
- Log how many assets were warmed and how many failed
- Only then start the HTTP server
If warming takes > 30 seconds (e.g., all sources are down), log a warning and proceed anyway — do not block startup indefinitely.
Configuration
# Comma-separated list of assets to warm on startup
WATCHED_ASSETS=XLM,USDC:GA5ZSEJYB37JRC5AVCIA5MOP4RHTM335X2KGX3IHOJAPP5RE34K4KZVN,yXLM:GARDNV3Q7YGT4AKSDF25LT32YSCCW4EV22Y2TV3I2PU2MMXJTEDL5T55
Implementation
// src/startup/cacheWarm.js
async function warmCache(assets, oracle) {
const results = await Promise.allSettled(
assets.map(({ code, issuer }) => oracle.fetchFreshPrice(code, issuer))
);
const succeeded = results.filter(r => r.status === 'fulfilled').length;
logger.info({ succeeded, total: assets.length }, 'Cache warm complete');
}
Call warmCache in src/index.js before server.listen().
Acceptance Criteria
Overview
After a deployment or Redis flush, the first request for each asset hits all three upstream sources simultaneously, adding 500–2000ms of latency and consuming rate-limited API quota. Cache warming on startup eliminates this cold-start penalty.
Behaviour
On startup, before the HTTP server binds:
config.watchedAssets(or.env)Promise.allSettled)If warming takes > 30 seconds (e.g., all sources are down), log a warning and proceed anyway — do not block startup indefinitely.
Configuration
Implementation
Call
warmCacheinsrc/index.jsbeforeserver.listen().Acceptance Criteria
WATCHED_ASSETSenv var parsed on startup.env.exampleupdated withWATCHED_ASSETS