Caching Architecture¶
This document describes the caching architecture in proxbox-api, including design decisions, flow diagrams, and configuration options.
Overview¶
proxbox-api implements a request-level caching layer for NetBox GET operations to reduce database load during sync operations. The cache is in-memory only and does not persist across restarts.
Cache Types¶
NetBox GET Cache¶
Located in proxbox_api/netbox_rest.py, this cache stores responses from NetBox REST API GET requests. It's designed to:
- Reduce redundant NetBox API calls during sync operations
- Provide automatic cache invalidation on mutations (POST/PATCH/PUT/DELETE)
- Offer observability through metrics endpoints
- Support both entry count and byte size limits
Proxbox Internal Cache¶
Located in proxbox_api/cache.py, this is a separate in-memory cache for internal Proxbox data structures. It's used for general-purpose caching within the application.
Cache Flow¶
GET Request Flow¶
sequenceDiagram
participant Svc as Sync Service
participant Cache as NetBox GET Cache
participant NetBox as NetBox API
Svc->>Cache: Request GET /api/dcim/devices/
Note over Cache: Prune expired entries (TTL)
Cache->>Cache: Check if cached
alt Cache Hit
Cache-->>Svc: Return cached records
Note over Cache: Increment hits metric
else Cache Miss
Cache-->>Svc: No cache entry
Note over Cache: Increment misses metric
Svc->>NetBox: GET /api/dcim/devices/
NetBox-->>Svc: Return records
Svc->>Cache: Store in cache (with size)
Note over Cache: Evict if needed (LRU)
end
Cache Invalidation Flow¶
sequenceDiagram
participant Svc as Sync Service
participant Cache as NetBox GET Cache
participant NetBox as NetBox API
Svc->>NetBox: PATCH /api/dcim/devices/55/
NetBox-->>Svc: Success
Svc->>Cache: Invalidate /api/dcim/devices/55/
Note over Cache: Find exact path matches
Note over Cache: Find parent list path
Note over Cache: Find direct children
Cache->>Cache: Remove invalidated entries
Note over Cache: Increment invalidations metric
Cache Configuration¶
| Environment Variable | Default | Description |
|---|---|---|
PROXBOX_NETBOX_GET_CACHE_TTL |
60.0 | Cache TTL in seconds (0 to disable) |
PROXBOX_NETBOX_GET_CACHE_MAX_ENTRIES |
4096 | Maximum number of cached entries |
PROXBOX_NETBOX_GET_CACHE_MAX_BYTES |
52428800 | Maximum cache size in bytes (50MB) |
PROXBOX_DEBUG_CACHE |
0 | Enable debug logging (1 to enable) |
Eviction Policy¶
The cache uses a Least Recently Used (LRU) eviction policy. When either the entry count limit or byte size limit is reached, the oldest entries (by cached timestamp) are evicted first.
Eviction Triggers¶
- TTL Expiry: Entries older than
PROXBOX_NETBOX_GET_CACHE_TTLseconds are automatically removed - Entry Count Limit: When
len(cache) >= max_entries, oldest entries are evicted - Byte Size Limit: When
current_bytes + new_entry > max_bytes, oldest entries are evicted
Eviction Order¶
flowchart TD
A[New entry to write] --> B{Entry count >= max?}
B -->|Yes| C[Evict oldest by timestamp]
B -->|No| D{Byte size >= max?}
D -->|Yes| E[Evict oldest by timestamp]
D -->|No| F[Write entry]
C --> F
E --> F
Cache Invalidation Strategy¶
Cache invalidation is precise (not prefix-based) to avoid over-invalidation:
- Updating
/api/dcim/devices/55/invalidates: - Exact path:
/api/dcim/devices/55/ - Parent list:
/api/dcim/devices/ -
Direct children (if any): none for detail paths
-
Updating
/api/dcim/devices/(list) invalidates: - Exact path:
/api/dcim/devices/ - Direct children:
/api/dcim/devices/1/,/api/dcim/devices/2/, etc.
This prevents the issue where updating device ID 1 would incorrectly invalidate device ID 10.
Metrics and Observability¶
Available Metrics¶
| Metric | Type | Description |
|---|---|---|
hits |
counter | Total cache hits |
misses |
counter | Total cache misses |
hit_rate |
gauge | Cache hit rate percentage |
invalidations |
counter | Number of cache invalidations |
evictions_ttl |
counter | Entries evicted due to TTL expiry |
evictions_size |
counter | Entries evicted due to entry limit |
evictions_bytes |
counter | Bytes evicted due to byte limit |
current_entries |
gauge | Current cached entry count |
current_bytes |
gauge | Current cache size in bytes |
max_entries |
gauge | Maximum allowed entries |
max_bytes |
gauge | Maximum allowed bytes |
Metrics Endpoints¶
GET /cache- Combined cache view with metricsGET /cache/metrics- JSON metricsGET /cache/metrics/prometheus- Prometheus format
Debug Logging¶
Enable detailed cache logging with:
bash
export PROXBOX_DEBUG_CACHE=1
This logs: - Cache HIT/MISS events - Cache DISABLED (TTL=0) - Cache EXPIRED events - Cache INVALIDATE events with count
Integration Points¶
The cache is integrated at the REST helper layer in proxbox_api/netbox_rest.py:
rest_list_async()- List resources with cachingrest_first_async()- Get first result with cachingrest_get_async()- Get single resource with cachingrest_create_async()- Create with cache invalidationrest_update_async()- Update with cache invalidationrest_delete_async()- Delete with cache invalidation
All sync services automatically benefit from this centralized cache layer without any changes needed.
Performance Considerations¶
Cache Hit Rate¶
A high cache hit rate (>70%) indicates effective caching. To improve hit rate:
- Increase TTL for stable data
- Adjust cache size limits for your workload
- Ensure queries are deterministic (same query = same cache key)
Memory Usage¶
The byte limit prevents unbounded memory growth. Monitor current_bytes metric to ensure adequate headroom.
Benchmarking¶
Run performance benchmarks in CI to detect regressions:
```bash
Example benchmark command¶
uv run pytest tests/ --benchmark-only ```
See the GitHub Actions workflow for automated benchmarking.