Handling Feed Revisions in a Transit Schedule Cache
From the earlier reference collection. Read the current software blog.
Keep fetched schedule versions identifiable, invalidate derived results according to their dependencies, and prevent searches from mixing revisions.
Store the source version with the cache
A cached timetable needs more than a retrieval timestamp. Record the source URL or identifier, retrieval time, and any revision marker the publisher provides, such as a version label, modification time, or content checksum. These values answer different questions: when did the cache fetch, and did the source content change?
If the source offers no revision marker, a checksum of the downloaded bytes can detect changes observed by your own fetcher. It cannot tell you when the publisher made the change, and insignificant formatting differences may produce a new checksum. Keep the method explicit so operators know what “changed” means.
Publish replacements atomically
Download and validate a candidate schedule in a separate location. Only after all required files pass validation should the application make the candidate active. This avoids a search seeing half of the old schedule and half of the new one. Retain the prior version long enough to diagnose regressions or roll back safely.
Use a version identifier throughout one search request. If the route index comes from revision R2 but stop times come from R1, the results may be internally inconsistent even if both files are valid on their own. A request should resolve against one complete snapshot.
Invalidate by dependency
Derived data often includes parsed tables, route indexes, stop-to-stop transfer maps, and cached search results. Track which source version each layer depends on. When a schedule revision changes, rebuild or invalidate the affected layers; a changed stop name might only require display indexes, while changed stop times can affect all searches that depend on those trips.
A practical cache key can include the schedule version, query parameters, and relevant service date. Then a result computed from R1 cannot accidentally satisfy a request after R2 becomes active. Avoid deleting every cache blindly if some layers are independent, but prefer a full rebuild when dependency tracking is not reliable.
Make staleness visible
Record the active revision and fetch time in diagnostics. A user searching for a later trip should not unknowingly receive results derived from an old timetable after the source has changed. On a failed refresh, continue serving the last complete revision if appropriate, but label its age internally and apply the product’s own staleness policy.
A public schedule lookup can help frame the consequence: an old cached departure may produce a plausible but wrong plan. Use a reader’s likely departure question to decide which derived results depend on schedule updates. GTFS defines schedule datasets and service-day concepts, making it a useful reference when the cached material uses that format; the lookup page alone does not identify its data source.