fifteen/shared/src/queue.ts

175 lines
5 KiB
TypeScript

import type { RoutingMode } from "./osm-tags.js";
// ─── Job data types ───────────────────────────────────────────────────────────
export interface DownloadPbfJobData {
type: "download-pbf";
citySlug: string;
geofabrikUrl: string;
expectedBytes?: number;
}
export interface ExtractPoisJobData {
type: "extract-pois";
citySlug: string;
pbfPath: string;
/** Optional bounding box [minLng, minLat, maxLng, maxLat] to clip PBF before tag-filtering */
bbox?: [number, number, number, number];
}
export interface GenerateGridJobData {
type: "generate-grid";
citySlug: string;
resolutionM: number;
}
export interface ComputeScoresJobData {
type: "compute-scores";
citySlug: string;
modes: RoutingMode[];
thresholds: number[];
/** Set after compute-routing children are dispatched (internal two-phase state). */
routingDispatched?: boolean;
/** When true, ingest-boris-ni is dispatched in Phase 1 to run alongside routing jobs. */
ingestBorisNi?: boolean;
/** When true, ingest-boris-hb is dispatched in Phase 1 to run alongside routing jobs. */
ingestBorisHb?: boolean;
}
export interface ComputeRoutingJobData {
type: "compute-routing";
citySlug: string;
mode: "walking" | "cycling" | "driving";
category: string;
}
export interface ComputeTransitJobData {
type: "compute-transit";
citySlug: string;
}
export interface BuildValhallaJobData {
type: "build-valhalla";
/** City being added/updated. Absent for removal-only rebuilds. */
citySlug?: string;
pbfPath?: string;
/** Optional bounding box [minLng, minLat, maxLng, maxLat] to clip PBF before building routing tiles */
bbox?: [number, number, number, number];
/** Slugs to drop from the global routing tile set before rebuilding */
removeSlugs?: string[];
}
export interface RefreshCityJobData {
type: "refresh-city";
citySlug: string;
geofabrikUrl: string;
resolutionM?: number;
/** Monotonically increasing counter incremented at each trigger; used in jobIds
* to prevent completed-job deduplication on re-runs. */
iter: number;
/** ID of the compute-scores job enqueued for this refresh; set after flow.add(). */
computeScoresJobId?: string;
}
export interface IngestBorisNiJobData {
type: "ingest-boris-ni";
citySlug: string;
}
export interface IngestBorisHbJobData {
type: "ingest-boris-hb";
citySlug: string;
}
export interface DownloadGtfsDeJobData {
type: "download-gtfs-de";
url: string;
/** Re-download even if data already exists */
force?: boolean;
/**
* Per-city bounding boxes [minLng, minLat, maxLng, maxLat] used to clip the
* GTFS feed after extraction. A stop is kept when it falls inside ANY of the
* bboxes (each already padded by a small buffer in refresh-city.ts).
* When absent the full feed is kept.
*/
bboxes?: [number, number, number, number][];
}
export type PipelineJobData =
| DownloadPbfJobData
| ExtractPoisJobData
| GenerateGridJobData
| ComputeScoresJobData
| ComputeRoutingJobData
| BuildValhallaJobData
| RefreshCityJobData
| IngestBorisNiJobData
| IngestBorisHbJobData
| DownloadGtfsDeJobData
| ComputeTransitJobData;
// ─── Job options (BullMQ-compatible plain objects) ────────────────────────────
export const JOB_OPTIONS: Record<PipelineJobData["type"], object> = {
"compute-transit": {
attempts: 1,
removeOnComplete: { age: 86400 * 7 },
removeOnFail: { age: 86400 * 30 },
},
"download-gtfs-de": {
attempts: 2,
backoff: { type: "fixed", delay: 10000 },
removeOnComplete: { age: 86400 * 7 },
removeOnFail: { age: 86400 * 30 },
},
"compute-routing": {
attempts: 2,
backoff: { type: "fixed", delay: 3000 },
removeOnComplete: { age: 86400 * 7 },
removeOnFail: { age: 86400 * 30 },
},
"download-pbf": {
attempts: 2,
backoff: { type: "fixed", delay: 5000 },
removeOnComplete: { age: 86400 * 7 },
removeOnFail: { age: 86400 * 30 },
},
"extract-pois": {
attempts: 1,
removeOnComplete: { age: 86400 * 7 },
removeOnFail: { age: 86400 * 30 },
},
"generate-grid": {
attempts: 1,
removeOnComplete: { age: 86400 * 7 },
removeOnFail: { age: 86400 * 30 },
},
"compute-scores": {
attempts: 1,
removeOnComplete: { age: 86400 * 7 },
removeOnFail: { age: 86400 * 30 },
},
"build-valhalla": {
attempts: 3,
backoff: { type: "fixed", delay: 60_000 },
removeOnComplete: { age: 86400 * 7 },
removeOnFail: { age: 86400 * 30 },
},
"refresh-city": {
attempts: 1,
removeOnComplete: { age: 86400 * 7 },
removeOnFail: { age: 86400 * 30 },
},
"ingest-boris-ni": {
attempts: 2,
backoff: { type: "fixed", delay: 5000 },
removeOnComplete: { age: 86400 * 7 },
removeOnFail: { age: 86400 * 30 },
},
"ingest-boris-hb": {
attempts: 2,
backoff: { type: "fixed", delay: 5000 },
removeOnComplete: { age: 86400 * 7 },
removeOnFail: { age: 86400 * 30 },
},
};