@@ -24,6 +24,7 @@ import {
2424 type RefreshWaysToEdgesResult ,
2525 refreshWaysToEdges as refreshWaysToEdgesDefault ,
2626 type WayEdge ,
27+ defaultOutputPath as waysToEdgesMapPath ,
2728} from "./jobs/traffic/ways-to-edges.js" ;
2829import {
2930 type WriteLiveTrafficResult ,
@@ -165,10 +166,11 @@ export interface CronSetupOptions {
165166 } ) => Promise < boolean > ;
166167 /**
167168 * Resolves the set of OSM way ids the live-speed writer currently covers.
168- * No default is wired: until the live-speed writer job supplies this (it
169- * already fetches the source feed, so it owns the covered-way-id list),
170- * the guard cron logs and skips the way-to-edge refresh rather than
171- * writing a map filtered down to nothing.
169+ * The entrypoint wires this to `fetchCoveredWayIds` (the same OpenConditions
170+ * speed feed the writer consumes) when OpenConditions is configured; when
171+ * absent, the startup/guard way-to-edge refresh logs and skips rather than
172+ * writing a map filtered down to nothing — the whole live-traffic chain then
173+ * stays disabled.
172174 */
173175 getCoveredWayIds ?: ( ) => Promise < Set < number > > ;
174176 /**
@@ -562,15 +564,6 @@ export function setupCron(options: CronSetupOptions): CronHandles {
562564 const ensureExtract = options . ensureTrafficExtract ?? ensureTrafficExtract ;
563565 const checkExtractStale = options . isTrafficExtractStale ?? isTrafficExtractStale ;
564566
565- const runTrafficExtractStartup = async ( ) : Promise < void > => {
566- try {
567- const result = await ensureExtract ( { logger : log } ) ;
568- log . info ( "traffic-extract: startup check complete" , { built : result . built } ) ;
569- } catch ( err ) {
570- log . error ( "traffic-extract: startup ensure failed" , { err : ( err as Error ) . message } ) ;
571- }
572- } ;
573-
574567 const refreshWaysToEdges = options . refreshWaysToEdges ?? refreshWaysToEdgesDefault ;
575568
576569 // The way_id → GraphId map only changes when the graph rebuilds (a rebuild
@@ -593,6 +586,23 @@ export function setupCron(options: CronSetupOptions): CronHandles {
593586 }
594587 } ;
595588
589+ const runTrafficExtractStartup = async ( ) : Promise < void > => {
590+ try {
591+ const result = await ensureExtract ( { logger : log } ) ;
592+ log . info ( "traffic-extract: startup check complete" , { built : result . built } ) ;
593+ } catch ( err ) {
594+ log . error ( "traffic-extract: startup ensure failed" , { err : ( err as Error ) . message } ) ;
595+ }
596+ // A build (above, or the guard's rebuild) refreshes the way→edge map, but a
597+ // traffic.tar that already exists from a prior boot leaves the map ungenerated
598+ // on first run — the live writer then can't load it. Bootstrap it here when
599+ // it's missing so the chain works without waiting for the next graph rebuild.
600+ if ( options . getCoveredWayIds && ! existsSync ( waysToEdgesMapPath ( ) ) ) {
601+ log . info ( "ways-to-edges: map missing at startup, bootstrapping" ) ;
602+ await runWaysToEdgesRefresh ( ) ;
603+ }
604+ } ;
605+
596606 const runTrafficExtractGuard = async ( ) : Promise < void > => {
597607 try {
598608 const stale = await checkExtractStale ( { logger : log } ) ;
0 commit comments