UNPKG

@golemio/pid

Version:
605 lines (468 loc) 28.5 kB
# Redis cache ## Cache pro načítání GTFS jízdních řádů ### files:gtfsStatic:* - Klíč `files:gtfsStatic:*`, kde `*` je název souboru, popř. cesta k souboru v případě ZIP archivu - Hodnota CSV/JSON jako string - TTL žádné - Retence dat až do úspěšného načtení GTFS jíždních řádů - Cache obsahuje všechny načtené soubory z ROPID FTP (viz [implementační dokumentace](../../implementation_documentation.md#files-gtfs-static#ropid-ftp-obecně)) - Menší soubory jsou ukládány pomocí `SET`, větší jsou streamovány pomocí knihovny [redis-wstream](https://github.com/jeffbski/redis-wstream) (`SET` + `APPEND`) - Menší soubory jsou následně načteny pomocí `GET`, větší jsou streamovány z Redisu do PSQL pomocí knihovny [redis-rstream](https://github.com/jeffbski/redis-rstream) (`GETRANGE`) ### Flowchart ```mermaid flowchart TD; redis_1[("Redis files:gtfsStatic:*")]; redis_2[("Redis files:gtfsStatic:*")]; redis_3[("Redis files:gtfsStatic:*")]; psql[("PSQL ropidgtfs_*_tmp")]; amqp_transformAndSaveData[AMQP transformAndSaveData]; initial["Zpráva z cronu, stažení z ROPID FTP"]; initial--SET malý soubor-->redis_1; initial--Wstream velký soubor-->redis_1; initial-->amqp_transformAndSaveData; amqp_transformAndSaveData--GET malý soubor<-->redis_2; amqp_transformAndSaveData--Rstream velký soubor<-->redis_2; amqp_transformAndSaveData--INSERT malý soubor-->psql; amqp_transformAndSaveData--COPY stream velký soubor-->psql; continue[Pokračování v načítání JŘ]; amqp_transformAndSaveData-->continue; cache_manager["DataCacheManager"]; continue-->cache_manager; cache_manager--Truncate-->redis_3; ``` ## Cache pro GTFS-RT feedy ### files:gtfsRt - Klíč `files:gtfsRt`, pomocný `files:gtfsRt_*_timestamp`, kde `*` je název feedu bez přípony - Hodnota je hash mapa, kde klíč je název feedu s příponou `.pb` - `trip_updates.pb` - `vehicle_positions.pb` - `pid_feed.pb` - `alerts.pb` - Hodnota v hash mapě je binární blob reprezentující specifický GTFS-RT feed - Hodnota v pomocném klíči je unix timestamp poslední aktualizace daného feed v milisekundách - TTL žádné - Retence dat aktivní, vždy uchováváme nejnovější feedy - Všechny feedy jsou ukládány pomocí `HSET`, pomocné timestampy pomocí `SET` - Feedy jsou nabízený přes API `/v2/vehiclepositions/gtfsrt/{feed}`, kde `{feed}` je název feedu s příponou `.pb` - Žádaný feed se načte pomocí `HGET` a vrátí se jako binární blob. Pokud feed neexistuje, vrátí se 404 - Pomocný timestamp se načte pomocí `GET` a vrátí se jako hodnota hlavičky `Last-Modified` převedená na ISO string. Pokud timestamp neexistuje, hodnota hlavičky bude unix timestamp 0 jako ISO string. Využívá se především pro monitoring a alerting - Feedy se generují nejméně 3x za minutu (rabín 2x) pomocí queue-message - Používají redis-mutex na zamykání, aby neběželo více shodných tasků v jeden okamžik - Pokud generování stíhá běžet rychleji, task se snaží do ±7 vteřin svého běhu spustit nové generování souborů (opět přes queue-message). ### Flowchart ```mermaid flowchart TD; redis_f_1[("Redis files:gtfsRt")]; redis_t_1[("Redis files:gtfsRt_*_timestamp")]; psql[("PSQL vehiclepositions_*, ropidvymi_*")]; connector[("OG Redis connector")]; repository["IE GtfsRtRedisRepository"]; get_gtfsrt["GET /v2/vehiclepositions/gtfsrt/$feed"]; initial["Zpráva z cronu, vygenerování feedů"]; initial--Select<-->psql; initial-->repository; repository--HSET *.pb-->redis_f_1; repository--SET *_timestamp-->redis_t_1; get_gtfsrt-->connector; connector--HGET *.pb<-->redis_f_1; connector--GET *_timestamp<-->redis_t_1; ``` ## Cache pro zpracování RT dat ### gtfsRunSchedule:* - key = `*${route_id}_${run_number}` - retence dat aktivne v tride `DataCacheManager` - TTL podle casu vygenerovane ho z methody `getNextExpireTimestamp` - hodnota je `string` - cache obsaguje data z tabulky ropidgtfs_precomputed_trip_schedule ```mermaid flowchart TD; psql[("PSQL ropidgtfs_precomputed_trip_schedule")]; redis_trip_schedule[("Redis gtfsRunSchedule:*")]; connector[("OG Redis connector")]; repository["IE RunTripsRedisRepository"]; propagateDelay["propagateDelay"]; repository<--GET*.runTuple--->propagateDelay; runManager["AbstractGTFSTripRunManager"] get_gtfsrt["GET /v2/departureboards"]; initial["Zpráva z vozidla"]; initial--process-->runManager; repository--GET*.runTuple<-->redis_trip_schedule; runManager--GET*.runTuple<-->repository; runManager--SET *.runTuple-->repository; repository--SET *.runTuple-->redis_trip_schedule; runManager--SELECT if not found in redis<-->psql; get_gtfsrt-->connector; connector--**MGET** *runTuple<-->redis_trip_schedule; ``` ### gtfsBlockSchedule:* - key = `*gtfs_block_id` - retence dat aktivne v tride `DataCacheManager` - TTL podle casu vygenerovane ho z methody `getNextExpireTimestamp` - hodnota je `string` - cache obsahuje data trip_stops podle gtfs block_id ```mermaid flowchart TD; psql[("PSQL ropidgtfs_stop_times")]; cache[("Redis gtfsBlockSchedule:*")]; repository["IE BlockStopsRedisRepository"]; updateDelay["updateDelay"]; updateGTFSTripId["updateGTFSTripId"]; tripStopsManager["tripStopsManager"]; initial["Zpráva z vozidla"]; initial--process-->updateGTFSTripId; updateGTFSTripId<--create cache for trip stops-->tripStopsManager; updateGTFSTripId-->updateDelay; updateDelay<--get/update cache for trip stops-->tripStopsManager; updateDelay-->propagateDelay; propagateDelay-->propagateTrainDelay; propagateTrainDelay<--get/update cache for trip stops-->tripStopsManager; repository--GET*.blockId<-->redis_trip_schedule; tripStopsManager--GET*.blockId<-->repository; tripStopsManager--SET *.blockId-->repository; repository--SET *.blockId-->cache; tripStopsManager--SELECT if not found in redis<-->psql; ``` ### gtfsDelayComputation:* - key = `*${gtfs_trip_id}` - TTL nastavovano na valid_to posledni pozice kdyz je znama kdyz ne tak na 30 min - hodnota je `json` - cache obsahuje informace o tripu - stop_times - shapes_anchor_points - shapes ### Flowchart ```mermaid flowchart TD; updateDelay["UpdateDelay Task"]; saveRunToDb["save*RunToDb Task"]; updateRunsGTFSTripId["updateRunsGTFSTripId Task"] processRegionalBusPositions["processRegionalBusPositions Task"] processRegionalBusRunMessages["processRegionalBusRunMessages Task"] repository["DelayComputationRedisRepository"]; cache["Redis gtfsDelayComputation:*"]; initial["Zprava z vozidla"] initial-->saveRunToDb saveRunToDb--common message-->updateRunsGTFSTripId updateRunsGTFSTripId-->updateDelay; updateDelay<--getTripPropertiesBatch-->repository; updateDelay<--cacheTripDataBatch-->repository; saveRunToDb--ArrivaCity run message-->processRegionalBusRunMessages processRegionalBusRunMessages-->processRegionalBusPositions processRegionalBusPositions<--getTripPropertiesBatch-->repository; processRegionalBusPositions<--cacheTripDataBatch-->repository; repository--JSON.GET-->cache repository--JSON.SET-->cache ``` ## Cache pro předzpracování a párování dat z Telmaxu (Arriva City) ### vpRegionalBusCisLookup:* - key = `*${external_trip_id}` - TTL podle casu vygenerovane ho z methody `getNextExpireTimestamp` - hodnota je string (JSON.stringify()) - cache obsahuje cis informace o tripu - cis_line_id - cis_trip_number - registration_number ```mermaid flowchart TD cache["vpRegionalBusCisLookup:*"] repo["RegionalBusCisCacheRepository"] telmax["Telmax (Arriva City)"] task["saveArrivaCityRunsToDB task"] telmax-->|bus position message|task task-->|lookup CIS ID|repo repo-->|get/set|cache task-->|update cache|repo cache-->|return data|repo ``` ### vpRegionalBusGtfsLookup:* - key = `*${cis_line_id}_${cis_trip_number}` - TTL zadne nema - retence dat aktivne v tride `DataCacheManager` - hodnota je string (JSON.stringify()) - cache obsahuje gtfs informace o tripu - gtfs_trip_id - route_name - run_number - agency_name - is_wheelchair_accessible ```mermaid flowchart TD cache["vpRegionalBusGtfsLookup:*"] repo["RegionalBusGtfsCacheRepository"] telmax["Telmax (Arriva City)"] task["processRegionalBusRunMessages Task"] psql["gtfs data in DB"] telmax-->|bus position message|task task<--No gtfs data for trip in cache-->psql task-->|lookup GTFS trip|repo repo-->|get/set|cache task-->|update cache|repo cache-->|return data|repo ``` ## Cache pro public API ### vpPublicCache:* - Hlavní komponentou je sorted set `vpPublicCache:$setId`, kde `$setId` je ID vygenerované datové sady (4 náhodné bajty reprentované hexadecimálně) - Score je GPS souřadnice (`GEOADD`), member je ID vozidla. Sorted set se používá jako základ pro public VP (`GEOSEARCH`) - ID nejnovější datové sady se propaguje přes PubSub channel `vpPublicCache` - Další komponenty: - `vpPublicCache:$setId:trip-$gtfsTripId` - list ID vozidel asociovaných s daným GTFS trip id (možnost více vozidel na jednom spoji) - `vpPublicCache:$setId:vehicle-$vehicleId` - JSON jako string s informacemi o vozidle a spoji, které vykonává - `vpPublicCache:$setId:future-trip-$gtfsTripId` - list ID vozidel asociovaných s daným GTFS trip id (možnost více vozidel na jednom spoji). Vozidlo je před trasou a vykonává předchozí spoj na oběhu (nemá se zobrazit na mapě). Využití v public odjezdech - `vpPublicCache:$setId:future-vehicle-$vehicleId-$gtfsTripId` - JSON jako string s informacemi o vozidle. Vozidlo je před trasou a vykonává předchozí spoj na oběhu (nemá se zobrazit na mapě). Využití v public odjezdech a public VP detailu s GTFS lookupem - `vpPublicCache:$setId:canceled-trips-$gtfsTripId` - JSON jako string s informacemi o zrušeném spoji. Využití v public odjezdech - TTL 1 minuta - Nová datová sada se generuje přibližně jednou za 3 vteřiny a obsahuje všechny RT spoje (aktivní, budoucí a zrušené) - Populace `future-trip-*`, `future-vehicle-*` a `canceled-trips-*` sub-klíčů je řízena stavem spoje (před trasou / zrušen) a nesouvisí s logikou deduplikace odjezdů v `/v2/public/departureboards` – ta pracuje nad `gtfsPublicDepartureCache` a tuto cache neovlivňuje ### vpPublicStopTimeCache:* - Klíč `vpPublicStopTimeCache:*`, kde `*` je kombinace ID vozidla a GTFS id spoje (možnost více vozidel na jednom spoji) - Hodnota je JSON jako string s informacemi o zastávkách a jejich časech - `sequence` - pořadí zastávky podle GTFS stop times - `arr_delay` - čas příjezdu na zastávku - reálný čas u projetých zastávek, predikce u budoucích - `dep_delay` - čas odjezdu ze zastávky - reálný čas u projetých zastávek, predikce u budoucích - `cis_stop_platform_code` - nástupiště/kolej podle CIS u vlakových zastávek, jinde null - `platform_code` - označení zastávky podle GTFS - `stop_id` - GTFS id zastávky - `stop_name` - název zastávky - TTL 1 hodina a 5 minut - Automatické promazání dat po úspěšném načtení GTFS jíždních řádů - Cca jednou za 5 vteřin se přenačtou stop times pro všechny aktivní spoje. Generování může běžet pouze jednou, po dokončení tasku se spustí znovu (max čekání 4.8 vteřin) ### gtfsPublicDepartureCache:* - Klíč `gtfsPublicDepartureCache:*`, kde `*` je GTFS id zastávky - Hodnota je sorted set, kde score je unix timestamp odjezdu v sekundách a member je JSON string s informacemi o odjezdu: - `stop_id` – GTFS id zastávky - `departure_datetime` – plánovaný čas odjezdu (ISO 8601) - `arrival_datetime` – plánovaný čas příjezdu (ISO 8601), nebo `null` - `route_short_name` – název linky - `route_type` – typ dopravy (GTFS route_type) - `trip_id` – GTFS id spoje - `stop_sequence` – pořadí zastávky v spoji - `platform_code` – označení nástupiště, nebo `null` - `trip_headsign` – cílová zastávka spoje (nebo `stop_headsign`, pokud je definován) - `trip_headsign_icons` – ikony přestupů u cílové zastávky jako řetězec dvouznaková kódů (např. `"MbMcSb"`), nebo `null` - `connections` – seznam garantovaných přestupů čekajících na tento spoj, nebo `null`; každý záznam obsahuje: - `from_trip_id` – GTFS id spoje, na který se čeká - `max_wait_sec` – maximální čekací doba v sekundách - Přednačítá se z tabulky `ropidgtfs_precomputed_trip_connections` (původně z `transfers.txt` kde `transfer_type = 1`), JOIN na odjezdy přes `to_trip_id` a `to_stop_id` - `wheelchair_accessible` – přístupnost vozidla pro vozíčkáře z GTFS `trips.txt` (`0` = bez informace, `1` = přístupné, `2` = nepřístupné), nebo `null` - `direction_id` – směr jízdy z GTFS `trips.txt` (`0` nebo `1`), nebo `null`; využívá se při seskupování odjezdů podle směru a filtrování opačného směru v přestupních tabulích - `flags` – nepovinný objekt s příznaky spoje, vyplněn pouze pokud má alespoň jeden z příznaků hodnotu `1` (zdroj `ropidgtfs_departures.is_night/is_regional/is_substitute_transport`); v objektu se objeví pouze pravdivé klíče: - `night` (`1`) – noční spoj - `reg` (`1`) – regionální spoj - `subst` (`1`) – náhradní doprava - Existuje záznam pro každou zastávku v GTFS. Pokud v ní ale není žádný odjezd, je vyplněný pouze jeden prázdný member - detekce validní zastávky bez odjezdu - TTL 7 hodin - Retence dat aktivní, jednou za hodinu se smažou všechny odjezdy starší než 3 hodiny - Jednou za hodinu se vygenerují nové odjezdy pro všechny zastávky v intervalu +5 hodin až +7 hodin, po přenačtení JŘ se přegenerují všechny odjezdy v interval -3 hodiny až +7 hodin - Ukládá se pomocí `ZADD`, čte se pomocí `ZRANGEBYSCORE` (-inf, now + `minutesAfter`) - Využití v public odjezdech - Využití v endpointu přestupních tabulí (`/v4/pid/transferboards`) ### Flowchart (refresh) ```mermaid flowchart LR; finish_up_gtfs["Dokončení zpracování GTFS JŘ"]; psql_rt[("PSQL vehiclepositions_*")]; psql_stop_times[("PSQL v_public_vehiclepositions_combined_stop_times")]; psql_departures[("PSQL ropidgtfs_departures")]; redis_pubsub_channel["Redis channel vpPublicCache"]; redis_public_cache[("Redis vpPublicCache:*")]; redis_stop_times[("Redis vpPublicStopTimeCache:*")]; redis_departures[("Redis gtfsPublicDepartureCache:*")]; amqp_refreshPublicTripCache[AMQP refreshPublicTripCache]; %% amqp_refreshPublicTripCache--"Čekání max 2.4 vteřin od spuštění tasku"-->amqp_refreshPublicTripCache; amqp_refreshPublicStopTimeCache[AMQP refreshPublicStopTimeCache]; %% amqp_refreshPublicStopTimeCache--"Čekání max 4.8 vteřin od spuštění tasku"-->amqp_refreshPublicStopTimeCache; amqp_refreshPublicGtfsDepartureCache[AMQP refreshPublicGtfsDepartureCache]; cron_public_cache["Cron public VP 1x za minutu (backup)"]; cron_public_cache-->amqp_refreshPublicTripCache; cron_stop_times["Cron zastávky spojů 1x za minutu (backup)"]; cron_stop_times-->amqp_refreshPublicStopTimeCache; cron_departures["Cron odjezdy 1x za hodinu"]; cron_departures--"{fromHours: 5, toHours: 7}"-->amqp_refreshPublicGtfsDepartureCache; finish_up_gtfs--"Truncate"-->redis_stop_times; finish_up_gtfs--"{fromHours: -3, toHours: 7}"-->amqp_refreshPublicGtfsDepartureCache; amqp_refreshPublicTripCache--"Aktivní spoje a jejich polohy"<-->psql_rt; amqp_refreshPublicTripCache--"GEOADD + RPUSH + SET"-->redis_public_cache; amqp_refreshPublicTripCache--"ID/název nové datové sady"-->redis_pubsub_channel; amqp_refreshPublicStopTimeCache--"Zastávky u všech aktivních spojů"<-->psql_stop_times; amqp_refreshPublicStopTimeCache--"MSET"-->redis_stop_times; amqp_refreshPublicGtfsDepartureCache--"Odjezdy v intervalu"<-->psql_departures; amqp_refreshPublicGtfsDepartureCache--"ZREMRANGEBYSCORE + ZADD"-->redis_departures; ``` ### Flowchart (public API VP) ```mermaid flowchart TD; redis_pubsub_channel["Redis channel vpPublicCache"]; redis_subscriber["VPSubscriber"]; redis_public_cache[("Redis vpPublicCache:* (RT info)")]; redis_public_cache_misc[("Redis vpPublicCache:* (aktivní, budoucí a zrušené spoje)")]; redis_repository["OG PublicVehiclePositionsRepository"]; redis_repository<-->redis_public_cache_misc; redis_repository<-->redis_public_cache; redis_subscriber--"Přihlášení k odběru"-->redis_pubsub_channel; redis_pubsub_channel--"ID/název nové datové sady"-->redis_subscriber--"setCurrentSetName"-->redis_repository; get_vp["GET /v2/public/vehiclepositions"]; get_vp--"GEOSEARCH + vehicle_id lookup pouze aktivních spojů"-->redis_repository; ``` ### Flowchart (public API VP detail) ```mermaid flowchart TD; redis_pubsub_channel["Redis channel vpPublicCache"]; redis_subscriber["VPSubscriber"]; redis_public_cache[("Redis vpPublicCache:* (RT info)")]; redis_public_cache_misc[("Redis vpPublicCache:* (aktivní, budoucí a zrušené spoje)")]; redis_stop_times[("Redis vpPublicStopTimeCache:*")]; redis_delay_computation[("Redis gtfsDelayComputation:* (pouze shapes)")]; redis_repository["OG PublicVehiclePositionsRepository"]; redis_repository<-->redis_public_cache_misc; redis_repository<-->redis_public_cache; redis_subscriber--"Přihlášení k odběru"-->redis_pubsub_channel; redis_pubsub_channel--"ID/název nové datové sady"-->redis_subscriber--"setCurrentSetName"-->redis_repository; get_vp_detail["GET /v2/public/vehiclepositions/$vehicle_id"]; get_vp_detail--"Lookup aktivního GTFS spoje"-->redis_repository; get_vp_detail--"scope[]=stop_times"<-->redis_stop_times; get_vp_detail--"scope[]=shapes"<-->redis_delay_computation; ``` ### Flowchart (public API VP detail with GTFS) ```mermaid flowchart TD; redis_pubsub_channel["Redis channel vpPublicCache"]; redis_subscriber["VPSubscriber"]; redis_public_cache[("Redis vpPublicCache:* (RT info)")]; redis_public_cache_misc[("Redis vpPublicCache:* (aktivní, budoucí a zrušené spoje)")]; redis_stop_times[("Redis vpPublicStopTimeCache:*")]; redis_delay_computation[("Redis gtfsDelayComputation:* (pouze shapes)")]; redis_repository["OG PublicVehiclePositionsRepository"]; redis_repository<-->redis_public_cache_misc; redis_repository<-->redis_public_cache; redis_subscriber--"Přihlášení k odběru"-->redis_pubsub_channel; redis_pubsub_channel--"ID/název nové datové sady"-->redis_subscriber--"setCurrentSetName"-->redis_repository; get_vp_detail_with_gtfs["GET /v2/public/vehiclepositions/$vehicle_id;gtfsTripId=$gtfsTripId"]; get_vp_detail_with_gtfs--"Lookup aktivního nebo budoucího GTFS spoje (exact match)"-->redis_repository; get_vp_detail_with_gtfs--"scope[]=stop_times"<-->redis_stop_times; get_vp_detail_with_gtfs--"scope[]=shapes"<-->redis_delay_computation; ``` ### Flowchart (public API GTFS static lookup) :warning: GTFS static lookup neřeší RT informace a jako jediný EP je napojený přímo na PSQL. Kvůli předpokládáně nižšímu využití (detail odjezdů v budoucnosti) to tolik nevadí ```mermaid flowchart TD; psql_trip[("PSQL ropidgtfs_trips, ropidgtfs_routes, ropidgtfs_precomputed_trip_schedule")]; psql_stop_times[("PSQL ropidgtfs_stop_times, ropidgtfs_stops")]; psql_shapes[("PSQL ropidgtfs_shapes")]; get_gtfs_detail["GET /v2/public/gtfs/trips/$trip_id"]; get_gtfs_detail--"Lookup GTFS trip id"<-->psql_trip; get_gtfs_detail--"scope[]=stop_times"<-->psql_stop_times; get_gtfs_detail--"scope[]=shapes"<-->psql_shapes; ``` ### Flowchart (public API departures) ```mermaid flowchart TD; redis_pubsub_channel["Redis channel vpPublicCache"]; redis_subscriber["VPSubscriber"]; redis_public_cache[("Redis vpPublicCache:* (RT info)")]; redis_public_cache_misc[("Redis vpPublicCache:* (aktivní, budoucí a zrušené spoje)")]; redis_departures[("Redis gtfsPublicDepartureCache:*")]; redis_repository["OG PublicVehiclePositionsRepository"]; redis_subscriber--"Přihlášení k odběru"-->redis_pubsub_channel; redis_pubsub_channel--"ID/název nové datové sady"-->redis_subscriber--"setCurrentSetName"-->redis_repository; get_departures["GET /v2/public/departureboards"]; get_departures--"Odjezdy pro zastávky"-->redis_departures; get_departures--"Aktivní vozidlo podle GTFS trip id"-->redis_repository<-->redis_public_cache_misc; rt_info["Obohacení o RT informace"]; get_departures--"Alespoň jedno vozidlo připadá nějakému spoji (aktivní, budoucí i zrušené) na odjezdu"-->rt_info; rt_info--"RT informace o spoji"-->redis_repository<-->redis_public_cache; ``` ## Cache pro API přestupních tabulí (transfer boards) *(přestupní tabule využívají také cache pro Public API, která je již popsána výše)* ### gtfsStopsCache:* - Jednotlivé komponenty cache jsou členěny do sad s `$setId` - `$setId` je id vygenerované datové sady (4 náhodné bajty reprezentované hexadecimálně) - Nová sada je vytvořena při každém přenačtení cache - Id `$setId` nejnovější datové sady se propaguje přes PubSub channel `gtfsStopsCache` a je také uloženo v cache jako hodnota položky `gtfsStopsCache:activeSetName` - Komponenty: - `gtfsStopsCache:$setId:aswNodeToGtfsStops` - Hash mapa, mapující daný ASW node na seznam pod něj spadajících zastávek (GTFS ids zastávek, odděleny čárkami) - `gtfsStopsCache:$setId:cisToAswNode` - Hash mapa, mapující dané CIS id zastávky na příslušný ASW node - TTL žádné (mimo přenačtení cache, kdy je namísto okamžitého promazání původnímu setu nastaveno TTL 1 minuta) - Cache je celá přenačtena vždy po přenačtení jízdních řádů (tedy 1-2x denně při stavu k červenci 2025) ### jisCache:* - Jednotlivé komponenty cache jsou členěny do sad s `$setId` - `$setId` je id vygenerované datové sady (4 náhodné bajty reprezentované hexadecimálně) - Nová sada je vytvořena při každém přenačtení cache - Id `$setId` nejnovější datové sady se propaguje přes PubSub channel `jisCache` a je také uloženo v cache jako hodnota položky `jisCache:activeSetName` - Komponenty: - `jisCache:$setId:infotexts` - Hash mapa, mapující dané id infotextu na informace o onom infotextu (JSON jako string) - `jisCache:$setId:stops-infotexts` - Hash mapa, mapující dané GTFS id zástavky na seznam infotextů s ní asociovaných (ids infotextů, odděleny čárkami) - TTL žádné (mimo přenačtení cache, kdy je namísto okamžitého promazání původnímu setu nastaveno TTL 1 minuta) - Cache je celá přenačtena při každé aktualizaci infotextů (tento proces je více popsán v [Dokumentaci propisu VYMI (JIS) dat do datové platformy](../../jis/index.md)) ### Flowchart (refresh gtfsStopsCache:*) ```mermaid flowchart LR finish_up_gtfs("`Dokončení zpracování GTFS JŘ`"); psql_ropidgtfs_cis_stops[("`PSQL ropidgtfs_cis_stops`")]; psql_ropidgtfs_stops[("`PSQL ropidgtfs_stops`")]; redis_gtfsStopsCache[("`Redis gtfsStopsCache:\*`")]; amqp_refreshGtfsStopsCache["`AMQP refreshGtfsStopsCache`"]; task_RefreshGtfsStopsCacheTask["`RefreshGtfsStopsCacheTask`"]; finish_up_gtfs --> amqp_refreshGtfsStopsCache; amqp_refreshGtfsStopsCache --> task_RefreshGtfsStopsCacheTask; task_RefreshGtfsStopsCacheTask <-- "`ASW ids a CIS ids zastávek`" --> psql_ropidgtfs_cis_stops; task_RefreshGtfsStopsCacheTask <-- "`ASW nodes a GTFS ids zastávek`" --> psql_ropidgtfs_stops; task_RefreshGtfsStopsCacheTask -- "`HSET gtfsStopsCache:$setId:aswNodeToGtfsStops a gtfsStopsCache:$setId:cisToAswNode, EXPIRE staré sady`" --> redis_gtfsStopsCache; ``` ### Flowchart (refresh jisCache:*) ```mermaid flowchart LR refresh_infotexts("`Aktualizace infotextů`"); psql_jis_infotexts[("`PSQL jis_infotexts`")]; psql_jis_infotexts_ropidgtfs_stops[("`PSQL jis_infotexts_ropidgtfs_stops`")]; redis_jisCache[("`Redis jisCache:\*`")]; amqp_refreshJISInfotextsCache["`AMQP refreshJISInfotextsCache`"]; task_RefreshJISInfotextsCacheTask["`RefreshJISInfotextsCacheTask`"]; refresh_infotexts --> amqp_refreshJISInfotextsCache; amqp_refreshJISInfotextsCache --> task_RefreshJISInfotextsCacheTask; task_RefreshJISInfotextsCacheTask <-- "`Data infotextů`" --> psql_jis_infotexts; task_RefreshJISInfotextsCacheTask <-- "`GTFS ids zastávek a ids infotextů`" --> psql_jis_infotexts_ropidgtfs_stops; task_RefreshJISInfotextsCacheTask -- "`HSET jisCache:$setId:infotexts a jisCache:$setId:stops-infotexts, EXPIRE staré sady`" --> redis_jisCache; ``` ### gtfsTripStopsCache:* - Klíč `gtfsTripStopsCache:*`, kde `*` je GTFS `trip_id` - Hodnota je JSON string s polem zastávek seřazených podle `stop_sequence`: - `stops` – pole dvojic `[stop_id, stop_name]` - TTL 6 hodin (musí přesáhnout maximální dobu jízdy spoje ~3,5h + interval tasku 1h) - Cache se přegeneruje jednou za hodinu (cron přes `EnsureCacheTask`) a po přenačtení GTFS jízdních řádů (přes `CheckSavedRowsAndReplaceTablesTask`) - SQL dotaz vybírá všechny spoje, jejichž první zastávka (`stop_sequence = 1`) má `departure_datetime` v okně `now() − 1h``now() + 2h`, a pro každý takový spoj agreguje všechny zastávky - Zapisuje `GtfsTripStopsCacheRepository` (IE) v dávkách po 200 klíčích přes Redis pipeline; před zápisem se validují data přes AJV schéma, nevalidní záznamy se přeskočí a zalogují - Čte `GtfsTripStopsRepository` (OG) přes `MGET` — využívá `TransferFacade.findRelevantTripIdsFromLines()` pro filtrování přestupních linek ### Flowchart (v4 transferboards API) ![flowchart.svg](../../assets/V4Transferboards.svg) link na .drawio [soubor](../../assets/V4Transferboards.drawio) ## Cache pro konfiguraci ### config:notPublicVehicles - Klíč `config:notPublicVehicles` (jednoduchý klíč, žádný wildcard) - Hodnota je JSON string struktury `INotPublicVehicles`: - `tram.registrationNumbers` – seznam evidenčních čísel tramvají bez platného GTFS spoje - `road.registrationNumbers` – seznam evidenčních čísel autobusů a trolejbusů bez platného GTFS spoje (`road` pokrývá obě kategorie, protože sdílejí číselnou řadu) - `routeIds` – whitelist čísel linek (např. `"861"` pro náhradní autobus X-C při výluce metra C) zobrazovaných i bez platného JŘ spoje - TTL žádné – hodnota se přepíše při každém spuštění `SaveStaticDataTask` (po načtení nových JŘ) - Zapisuje `NotPublicVehiclesRedisRepository` (IE), čte `TripsRepository` / `PositionsMapper` (IE) a `UpdateRunsGtfsTripIdTask` (IE) pro povolení průchodu vozidel bez GTFS spoje ## Manuální refresh cache (EnsureCacheTask) `EnsureCacheTask` slouží jako manuální spouštěč obnovy všech 5 caches, jejichž data nejsou real-time obnovována. Po přijetí prázdné zprávy na frontě `vehicle-positions.ropidgtfs.ensureCache` odešle paralelně prázdné zprávy do všech 5 cílových front. Dvě z nich míří do různých workerů (cross-worker routing přes RabbitMQ exchange), tři míří do stejného workeru (TimetableWorker). ### Flowchart ```mermaid flowchart LR trigger["`Zpráva do fronty ensureCache`"] task["`EnsureCacheTask (TimetableWorker)`"] exchange_vp["`Exchange ${RABBIT_EXCHANGE_NAME}.vehiclepositions (VPWorker)`"] exchange_self["`Exchange this.queuePrefix (TimetableWorker)`"] exchange_jis["`Exchange ${RABBIT_EXCHANGE_NAME}.jis (JISWorker)`"] q1["`AMQP refreshGTFSTripData`"] q2["`AMQP refreshPublicGtfsDepartureCache`"] q3["`AMQP refreshGtfsStopsCache`"] q4["`AMQP refreshGtfsTripStopsCache`"] q5["`AMQP refreshJISInfotextsCache`"] trigger --> task task -- cross-worker --> exchange_vp --> q1 task -- same-worker --> exchange_self --> q2 exchange_self --> q3 exchange_self --> q4 task -- cross-worker --> exchange_jis --> q5 ```