cdn module provides multi-source Content Delivery Network (CDN) management. It includes automatic fallback, health tracking, circuit breaker patterns, and source selection. Data fetching continues when individual CDN sources fail, experience outages, or degrade in performance.
Overview
The CDN system is a core component of tif1’s data fetching infrastructure. It is designed for availability, reliability, and performance when it retrieves Formula 1 data from remote sources. The system implements circuit breaker logic, automatic failover, health monitoring, and priority-based routing. These patterns keep the application operational under adverse network conditions.Why CDN Management Matters
Formula 1 data fetching presents unique challenges:- Data availability: Historical and live session data must be reliably accessible across multiple seasons (2018-2026+)
- Geographic distribution: Users worldwide need fast access regardless of location
- Network resilience: CDN providers can experience outages, rate limiting, or degraded performance
- Bandwidth optimization: Session data can be large (telemetry, lap times, weather data)—minification reduces transfer sizes by 20-40%
- Cost efficiency: Proper CDN selection and fallback minimize redundant requests and bandwidth waste
Core Capabilities
1. Multi-Source Fallback with Automatic Failover
The CDN manager maintains a prioritized list of CDN sources and automatically tries alternative sources when the primary source fails. This ensures high availability even when individual CDN providers experience issues. How it works:- Sources are tried in priority order (lowest priority number first)
- If a source fails, the next available source is tried immediately
- Successful requests reset the failure counter for that source
- Failed sources are temporarily disabled after reaching the failure threshold
- Zero-downtime failover: Automatic switching to backup sources without user intervention
- Transparent recovery: Sources automatically re-enable after successful requests
- Configurable priorities: Define preferred CDN providers based on performance, cost, or geographic location
2. Health Tracking and Circuit Breaker Pattern
Each CDN source is continuously monitored for reliability. The circuit breaker pattern prevents wasting time on consistently failing sources by temporarily disabling them after repeated failures. Circuit breaker states:- Closed (healthy): 0-2 failures—source is available and used normally
- Open (disabled): 3+ failures—source is excluded from
get_sources()until reset - Half-open (recovering): After a successful request, failure count resets to 0
- Default: 3 consecutive failures before disabling
- Configurable via
_max_failuresattribute - Failures are tracked per-source in
_failure_countsdictionary
- Reduced latency: Skip known-bad sources instead of waiting for timeouts
- Prevent cascading failures: Isolate failing sources to protect overall system health
- Automatic recovery: Sources re-enable after successful requests (self-healing)
3. Priority-Based Routing
Sources are assigned priority levels (integer values, lower = higher priority) that determine the order in which they are tried. Priority levels support these strategies:- Optimize for performance: Set fastest CDN as priority 1
- Optimize for cost: Set free/unlimited CDN as priority 1, paid CDN as backup
- Optimize for geography: Set regional CDN as priority 1 for users in that region
- Implement tiered fallback: Primary (priority 1) → Regional backup (priority 2) → Global backup (priority 3)
- Sources are sorted by priority (ascending order: 1, 2, 3, …)
- Sources with the same priority maintain their insertion order
- Priority can be set when creating
CDNSourceobjects - Sources are automatically re-sorted when added via
add_source()
4. JSON Minification Support
Optional JSON minification reduces file sizes by 20-40% by removing whitespace and formatting. This improves download speeds and reduces bandwidth costs, especially for large telemetry datasets. How it works:- When
use_minification=True, URLs are transformed:file.json→file.min.json - jsDelivr CDN automatically serves minified versions when available
- Minification is transparent—parsed data is identical to non-minified versions
- Can be enabled globally via config or per-source
- Hugging Face bucket sources never use minification. These sources do not serve
.min.json. A 404 there would waste a round trip on every request, so these sources are always excluded from minification
- Telemetry data: ~35-40% size reduction (structured, repetitive data)
- Lap data: ~25-30% size reduction
- Session metadata: ~20-25% size reduction
- Network transfer time: Proportional to size reduction (40% smaller = 40% faster download)
- Bandwidth-constrained environments: Mobile networks, metered connections
- High-volume applications: Fetching data for multiple sessions/drivers
- Performance-critical applications: Minimizing cold-start latency
- Cost optimization: Reducing CDN bandwidth costs
5. Configurable Custom Sources
Add custom CDN endpoints to support:- Private mirrors: Host a private copy of F1 data for guaranteed availability
- Regional CDNs: Optimize performance for specific geographic regions
- Corporate proxies: Route requests through internal infrastructure
- Development/testing: Point to local servers or staging environments
- Backup sources: Add redundant sources for applications that require high availability
- Programmatic: Use
add_source()method to add sources at runtime - Config file: Define sources in
~/.tif1rcJSON configuration - Environment variable: Set
TIF1_CDNScomma-separated list
6. Singleton Pattern for Global State
The CDN manager uses a singleton pattern to ensure consistent state across the entire application:- Single source of truth: All data fetching operations use the same CDN manager instance
- Shared health tracking: Failure counts and circuit breaker state are global
- Consistent configuration: Configuration changes affect all subsequent requests
- Thread-safe reads: Multiple threads can safely read CDN sources
- Memory efficient: Only one CDN manager instance exists per process
7. Transparent Integration
The CDN system operates in the background. Applications typically do not interact with it directly:- Automatic initialization: CDN manager is created on first use
- Zero-configuration default: Works out-of-the-box with the jsDelivr → Hugging Face → StaticDelivr chain
- Session API integration:
Session.load()automatically uses CDN system - Error handling: Network errors are caught and trigger automatic fallback
- Logging: Debug-level logs show which CDN source is being used
Architecture
The CDN system consists of three main components working together:1. CDNSource (Data Class)
Represents a single CDN endpoint with configuration:- Store CDN configuration (URL, priority, settings)
- Format complete URLs for specific resources via
format_url() - Support minification by transforming file paths
2. CDNManager (Orchestrator)
Manages multiple CDN sources and implements fallback logic:- Initialize sources from configuration (file, env vars, defaults)
- Validate source URLs (HTTPS only, block raw.githubusercontent.com)
- Track health via failure counters (circuit breaker pattern)
- Provide available sources via
get_sources()(filters disabled/failed sources) - Implement fallback logic via
try_sources()(tries sources in priority order). Async fetchers use the async counterparttry_sources_async(year, gp, session, path, fetch_func). It walks the same source chain with awaitable fetch functions - Manage source lifecycle (add, enable, disable, reset)
3. Global Singleton
A singleCDNManager instance shared across the application:
- Ensure consistent CDN state across all data fetching operations
- Provide global access point via
get_cdn_manager()function - Initialize once on first import, reuse for all subsequent calls
Data Flow
Here’s how a typical data fetch flows through the CDN system:When to Use This API
Most users never need to interact with the CDN API directly. It works transparently in the background. Use this API in these situations:Direct Interaction Scenarios
-
Adding custom CDN sources: Add a private mirror, regional CDN, or backup source
-
Monitoring CDN health: Track which sources are failing, or build health dashboards
-
Debugging network issues: Understand which CDN is used or why requests fail
-
Optimizing bandwidth: Enable minification for faster downloads
-
Testing fallback behavior: Verify that the application handles CDN failures gracefully
-
Implementing custom retry logic: Build a custom data fetching layer
-
Recovering from widespread failures: The network was down, and all sources now need a reset
Configuration Scenarios
- Setting up regional CDNs: Optimize performance for specific geographic regions
- Implementing cost optimization: Use free CDN as primary, paid CDN as backup
- Corporate environments: Route through internal proxies or mirrors
- Development/testing: Point to local servers or staging environments
- High-availability requirements: Add multiple backup sources for production applications
The default configuration uses three sources in priority order. The sources are jsDelivr (primary), Hugging Face buckets (
https://huggingface.co/buckets/tracinginsights, fallback), and StaticDelivr (last resort):- Global performance: 800+ CDN locations worldwide
- Unlimited bandwidth: No rate limits or bandwidth caps
- Automatic caching: Cache invalidation and purging
- HTTP/2 and HTTP/3 support: Modern protocols for faster transfers
- Minification support: Automatic
.min.jsonserving on jsDelivr - Hugging Face backup: Mirrors of the TracingInsights data repos that stay available when GitHub-sourced CDNs are down
Quick Start
For most use cases, the CDN API needs no direct interaction. It works transparently in the background. These common operations serve advanced use cases:Basic Usage (Transparent)
Inspecting CDN Status
Adding Custom CDN Sources
Enabling Minification
Monitoring and Recovery
Configuration via File
Instead of programmatic configuration, define CDN sources in~/.tif1rc:
Configuration via Environment Variables
API Reference
Module-Level Functions
get_cdn_manager()
CDNManager object, ensuring consistent CDN state across the entire application.
Why Singleton Pattern?
The singleton pattern is used because:
- Shared health tracking: CDN health monitoring must be consistent across all data fetching operations
- Global configuration: Configuration changes should affect all subsequent requests
- Consistent failure counts: Circuit breaker state must be global to prevent redundant retries
- Memory efficiency: Only one CDN manager instance exists per process
- Thread safety: Single instance simplifies concurrent access patterns
CDNManager: The global singleton instance
- Thread-safe operations:
get_sources(), readingsourceslist, reading_failure_counts - Not thread-safe:
add_source(),mark_failure(),mark_success(),reset()
- Configure all sources during initialization (single-threaded)
- Only read sources during concurrent execution
- Use locks to modify sources from multiple threads
CDNManager Class
TheCDNManager class is the core orchestrator of the multi-source CDN system. It maintains a list of CDN sources and tracks their health. It implements fallback logic with circuit breaker patterns. It also provides methods for managing sources.
Initialization
The CDN manager initializes automatically on the first call toget_cdn_manager(). During initialization, the following steps occur:
Initialization Sequence:
- Load configuration: Reads CDN sources from config file (
~/.tif1rc) or environment variables (TIF1_CDNS) - Parse source URLs: Splits comma-separated CDN URLs into individual sources
- Validate sources: Ensures all URLs are HTTPS and not blacklisted (for example,
raw.githubusercontent.com) - Create CDNSource objects: Wraps each URL in a
CDNSourcewith priority and settings - Assign priorities: Sources are assigned priorities based on their order (1, 2, 3, …)
- Initialize health tracking: Sets up
_failure_countsdictionary with all sources at 0 failures - Sort by priority: Orders sources so highest-priority (lowest number) is tried first
- Fallback to defaults: If no valid sources found, uses jsDelivr, Hugging Face buckets, and StaticDelivr as defaults
- Environment variable:
TIF1_CDNS(comma-separated list of HTTPS URLs) - Config file:
~/.tif1rcin home directory or current directory (ifTIF1_TRUST_CWD_CONFIG=true) - Default:
https://cdn.jsdelivr.net/gh/TracingInsights,https://huggingface.co/buckets/tracinginsights, andhttps://cdn.staticdelivr.com/gh/TracingInsights(in priority order)
- URLs must start with
https://(HTTP is rejected for security) - URLs containing
raw.githubusercontent.comare rejected (rate limits) - Invalid URLs are logged as warnings and skipped
- If all URLs are invalid, falls back to the default jsDelivr → Hugging Face → StaticDelivr chain
~/.tif1rc:
Attributes
sources
- Always sorted: Maintained in priority order (1, 2, 3, …)
- Includes all sources: Both
enabled=Trueandenabled=Falsesources - Includes failed sources: Sources that have exceeded failure threshold
- Mutable: Can be modified directly, but prefer using
add_source()for automatic sorting
- Iterate over all sources (including disabled) for health reporting
- Count total configured sources
- Inspect source configuration (URLs, priorities, settings)
- Debug CDN setup
_failure_counts
_max_failures (default: 3), it is automatically excluded from get_sources() until reset.
Structure:
- Initialized to 0: All sources start with 0 failures (healthy state)
- Incremented on failure:
mark_failure()increments the count - Reset on success:
mark_success()resets to 0 - Circuit breaker threshold: Sources with count >=
_max_failuresare excluded - Persistent across requests: Counts persist for the lifetime of the CDN manager instance
mark_failure(source_name)to incrementmark_success(source_name)to resetreset()to reset all sources
_max_failures
- Closed (healthy):
failure_count < _max_failures→ Source is available - Open (disabled):
failure_count >= _max_failures→ Source is excluded fromget_sources() - Half-open (recovering): After
mark_success(), count resets to 0 → Source becomes available again
- Not too sensitive: Tolerates transient network issues (1-2 temporary failures)
- Not too lenient: Quickly disables consistently failing sources (3 failures = clear pattern)
- Fast recovery: Single successful request resets the counter
Methods
get_sources()
- Disabled sources: Sources with
enabled=False - Failed sources: Sources where
_failure_counts[name] >= _max_failures(circuit breaker open)
list[CDNSource]: Available sources sorted by priority (ascending)- Empty list if all sources are disabled or have exceeded failure threshold
- Sources are sorted by priority: 1, 2, 3, … (lower number = higher priority)
- Sources with the same priority maintain their insertion order (stable sort)
- The first source in the list is tried first by
try_sources()
- Data fetching: Primary method used by
try_sources()to determine which sources to try - Health monitoring: Check how many sources are now available
- Debugging: Understand which sources the next request uses
- Load balancing: Implement custom logic based on available sources
add_source()
sources list in priority order, and its failure count is initialized to 0.
This method is useful for:
- Adding private CDN mirrors
- Adding regional CDN endpoints for better performance
- Adding backup sources for increased reliability
- Testing custom CDN configurations
source(CDNSource): The CDN source object to add
- Sources are automatically sorted by priority after insertion
- If a source with the same name already exists, both are kept (consider using unique names)
- The new source is immediately available for use via
get_sources() - Failure count is initialized to 0 (healthy state)
mark_failure()
get_sources() until reset.
This implements a circuit breaker pattern to prevent wasting time on consistently failing sources. The circuit breaker helps:
- Reduce latency by skipping known-bad sources
- Prevent cascading failures
- Allow sources to recover (via
reset()ormark_success())
source_name(str): Name of the CDN source that failed
- Increments failure count by 1
- If count reaches
_max_failures(3), logs a warning - Source is automatically excluded from
get_sources()after threshold - Does not disable the source permanently—can be recovered via
reset()ormark_success()
try_sources() calls this method automatically when a CDN request fails. Call it manually only for custom fetching logic.
Example:
mark_success()
source_name(str): Name of the CDN source that succeeded
- Sets failure count to 0 for the specified source
- Source becomes immediately available via
get_sources()if it was disabled - Called automatically by
try_sources()on successful fetch
try_sources() calls this method automatically when a CDN request succeeds. Applications rarely need to call it manually.
Example:
reset()
- After network outage: When the network connection was down and all sources failed
- After CDN maintenance: When CDN providers have resolved their issues
- Testing: To test fallback behavior from a clean state
- Manual recovery: To force retry of all sources
- Resets failure count to 0 for every source in
cdn.sources - All sources become immediately available via
get_sources()(ifenabled=True) - Does not modify source configuration (priority, URLs, minification settings)
try_sources()
- Get available sources: Calls
get_sources()to get enabled, healthy sources sorted by priority - Check availability: If no sources available, raises
NetworkErrorimmediately - Try each source (in priority order):
- Format URL via
source.format_url(year, gp, session, path) - Log debug message:
"Trying CDN: {source.name} - {url}" - Call
fetch_func(url)to try the HTTP request - On success: Call
mark_success(source.name)and return data (done!) - On
DataNotFoundError(404): Fall through to the next source. The failure count is NOT incremented (a 404 is not a CDN health problem). - On other exceptions: Log warning, call
mark_failure(source.name), try next source
- Format URL via
- All sources failed: Raise
DataNotFoundErrorif every failure was a 404; otherwiseNetworkErrorwith details from last exception
year(int): Season year (for example, 2021, 2022, 2023)gp(str): Grand Prix name, URL-encoded (for example, “Belgian%20Grand%20Prix”, “Monaco%20Grand%20Prix”)- Important: Must be URL-encoded (spaces as
%20, not+) - Use
urllib.parse.quote()if encoding manually
- Important: Must be URL-encoded (spaces as
session(str): Session name (for example, “Race”, “Qualifying”, “Practice 1”, “Sprint”)path(str): Resource path relative to session directory (for example, “drivers.json”, “laps.json”, “telemetry.json”)fetch_func(Callable[[str], Any]): Function that takes a URL string and returns fetched data- Should raise
DataNotFoundErrorfor 404 responses - Should raise other exceptions for network/server errors
- Return type can be any (dict, list, bytes, etc.)
- Should raise
Any: Fetched data from the first successful CDN source (return type depends onfetch_func)
DataNotFoundError: If every CDN source returned 404 for the resource- Raised only after all sources were tried
- Indicates the requested data does not exist on any mirror
NetworkError: If all CDN sources failed with non-404 errors- Includes URL path and status code from last exception
- Indicates all sources are unavailable or experiencing issues
-
Data not found (404): Possibly a stale or divergent mirror
- Falls through to the next CDN source (the payload may exist elsewhere)
- Does NOT increment failure counter (not a CDN health problem)
- If every source 404s, raises
DataNotFoundError
-
Network/server errors: Temporary error—CDN source is failing
- Logged as warning
- Failure counter incremented via
mark_failure() - Next source is tried
- If all sources fail, raises
NetworkError
- Latency: Each failed source adds latency (timeout + retry time). Use reasonable timeouts in
fetch_func. - Circuit breaker: After 3 failures, sources are automatically disabled, reducing latency for subsequent requests.
- Minification: Enable
use_minification=Trueto reduce download time by 20-40%. - Connection pooling: Reuse HTTP sessions in
fetch_funcfor better performance. - Parallel fetching:
try_sources()is sequential. For parallel fetching of multiple resources, call it multiple times concurrently.
try_sources()is thread-safe for concurrent calls- Failure counters are updated atomically (though not with locks)
- In high-concurrency scenarios, consider external synchronization for
mark_failure()/mark_success()calls
CDNSource
Dataclass representing a CDN source configuration.Constructor
name: Human-readable source namebase_url: Base URL for the CDN (must be HTTPS)priority: Priority level (lower number = higher priority, default: 0)enabled: Whether source is now enabled (default: True)use_minification: Enable JSON minification (appends.minbefore.json, default: False)
Methods
format_url()
year: Season year (for example, 2021)gp: Grand Prix name, URL-encoded (for example, “Belgian%20Grand%20Prix”)session: Session name (for example, “Race”, “Qualifying”)path: Resource path (for example, “drivers.json”)
- Complete CDN URL string
use_minification=True and path ends with .json, the path is transformed from file.json to file.min.json.
Example:
Configuration
CDN behavior can be configured via the global config:Practical Example: 2021 Belgian Grand Prix
Here’s a complete example showing how the CDN system works when fetching data for the 2021 Belgian Grand Prix Race:Best Practices
Configuration
- Use HTTPS only: HTTP CDN sources are rejected for security
- Enable minification: Reduces bandwidth by 20-40% for large datasets
- Configure via file: Use
~/.tif1rcfor persistent configuration - Set priorities wisely: Lower number = higher priority (1 before 2)
Error Handling
- Distinguish error types: Handle
DataNotFoundError(404) vsNetworkError(all sources failed) - Let CDN manager handle fallback: Do not implement custom retry logic
- Log failures: Enable debug logging to see which CDN is being used
Performance
- Enable minification: Especially for telemetry data (35-40% size reduction)
- Use connection pooling: Reuse HTTP sessions in fetch functions
- Set reasonable timeouts: Balance between patience and responsiveness
- Monitor circuit breaker: Check failure counts to identify problematic sources
Reliability
- Add backup sources: At least 2-3 sources for production applications
- Use regional CDNs: Optimize for the user’s geographic location
- Implement auto-recovery: Periodically reset sources after network issues
- Monitor health: Track availability and failure rates
Security
- Never use raw.githubusercontent.com: Rate limited and blocked by tif1
- Validate custom CDN URLs: Ensure they are trusted sources
- Use HTTPS everywhere: HTTP sources are automatically rejected
- Audit CDN sources: Regularly review configured sources
Troubleshooting
All CDN Sources Failing
Symptoms:NetworkError: All CDN sources failed
Solutions:
- Check network connectivity:
ping cdn.jsdelivr.net - Verify CDN URLs are accessible in browser
- Reset all sources:
cdn.reset() - Check firewall/proxy settings
- Enable debug logging to see detailed errors
Data Not Found (404)
Symptoms:DataNotFoundError: Data not found
Cause: Requested data does not exist (not a CDN failure)
Solutions:
- Verify session exists: Check year, GP name, session name
- Check data availability: Some sessions may not have all data types
- Use correct path: Ensure
pathparameter is correct (for example, “drivers.json”)
Slow Performance
Symptoms: Data fetching is slow Solutions:- Enable minification:
config.set("cdn_use_minification", True) - Add regional CDN: Closer to the user’s geographic location
- Check network speed: Run speed test
- Use connection pooling: Reuse HTTP sessions
- Increase timeout: May be timing out prematurely
Circuit Breaker Stuck Open
Symptoms: Sources remain disabled after network recovery Solution: Reset failure countsRelated APIs
- HTTP Session API: Underlying HTTP client used by CDN system
- Retry API: Retry logic and circuit breaker patterns
- Config API: CDN configuration management
- Exceptions API: NetworkError and DataNotFoundError details