From e7b8208edfd4e4b39d4542812e22d1076cf717a8 Mon Sep 17 00:00:00 2001 From: Fred Boniface Date: Wed, 24 Apr 2024 20:29:50 +0100 Subject: [PATCH] Add retry to LDB Staff lookup Signed-off-by: Fred Boniface --- src/services/.trainService.services.ts | 225 ------------------------- src/services/ldb.services.js | 40 ++++- 2 files changed, 31 insertions(+), 234 deletions(-) delete mode 100644 src/services/.trainService.services.ts diff --git a/src/services/.trainService.services.ts b/src/services/.trainService.services.ts deleted file mode 100644 index 5cd0d45..0000000 --- a/src/services/.trainService.services.ts +++ /dev/null @@ -1,225 +0,0 @@ -const db = require("./dbAccess.services"); -const clean = require("../utils/sanitizer.utils"); -const pis = require("../services/pis.services"); - -import { logger } from "../utils/logger.utils"; - -import type { TrainServices, Service, Stop } from "@owlboard/ts-types"; - -// This function is deprecated and should no longer be used. -// It will be removed in a later version -async function findByHeadcodeToday(headcode: string) { - const sanitizedHeadcode = clean.removeNonAlphanumeric(headcode).toUpperCase(); - logger.debug( - `trainServiceServices.findByHeadcode: Searching for headcode ${sanitizedHeadcode}` - ); - const now = new Date(); - const dayMap = ["su", "m", "t", "w", "th", "f", "s"]; - const shortDay = dayMap[now.getDay()]; // Fetch short day from map - const query = { - headcode: sanitizedHeadcode, - scheduleStartDate: { $lte: now }, - scheduleEndDate: { $gte: now }, - daysRun: { $in: [shortDay] }, - }; - const queryData = await db.query("timetable", query); - let trainData = await parseTrains(queryData); - let preparedData = []; - for (let trainService in trainData) { - if (pis.supported.includes(trainService?.operator)) { - // Search for PIS Code for each service - const tiplocList = await getPublicStops(trainService?.stops); - //console.log(tiplocList.length); console.log(tiplocList); - if (tiplocList.length) { - const pisDetail = await pis.findByTiplocArray(tiplocList); - trainService["pis"] = pisDetail?.[0]?.["code"] ?? "None"; - } else if (trainService?.operator === "GW") { - trainService["pis"] = "0015"; // Not in Service code - // '0015' is a string becuase 0015 is not a valid number.. - } - } - preparedData.push(trainService); - } - return preparedData; -} - -// Finds a train by its headcode value -async function findByHeadcode( - date: string | Date, - headcode: string -): Promise { - const sanitizedHeadcode = clean.removeNonAlphanumeric(headcode).toUpperCase(); - logger.debug( - `trainServiceServices.findByHeadcode: Searching for headcode ${sanitizedHeadcode}` - ); - let searchDate; - if (date === "now") { - searchDate = new Date(); - } else { - searchDate = new Date(date); - } - searchDate.setHours(12, 0, 0); // Set to midday to avoid any timezone issues - const dayMap = ["su", "m", "t", "w", "th", "f", "s"]; - const shortDay = dayMap[searchDate.getDay()]; // Fetch short day from map - const query = { - headcode: sanitizedHeadcode, - scheduleStartDate: { $lte: searchDate }, - scheduleEndDate: { $gte: searchDate }, - daysRun: { $in: [shortDay] }, - }; - const pipeline = [ - { - $match: query, - }, - { - $project: { - operator: 1, - stops: { - $concatArrays: [ - [{ $first: "$stops" }], - [{ $arrayElemAt: ["$stops", -1] }], - ], - }, - trainUid: 1, - stpIndicator: 1, - }, - }, - ]; - const queryData: Service[] = await db.queryAggregate("timetable", pipeline); - let filteredData = filterServices(queryData); - return await filteredData; -} - -// Finds a train by its trainUid value -async function findByTrainUid( - uid: string, - date: Date | string = new Date() -): Promise { - let queryDate; - if (date === "now") { - queryDate = new Date(); - } else { - queryDate = date; - } - const query = { - trainUid: uid, - scheduleStartDate: { $lte: queryDate }, - scheduleEndDate: { $gte: queryDate }, - }; - const queryData = await db.query("timetable", query); - if (queryData.length === 0) { - return queryData; - } - let services; - services = await filterServices(queryData); - console.log(services); - let publicStops; - if (pis.supported.includes(services[0]?.operator)) { - publicStops = await getPublicStops(services[0]?.stops); - if (publicStops.length) { - const pisCode = await pis.findByTiplocArray(publicStops); - services[0].pis = pisCode[0]?.code; - } else if (services[0]?.operator === "GW" && !publicStops.length) { - services[0].pis = "0015"; - } - } - return services[0]; -} - -module.exports = { - findByHeadcodeToday, - findByHeadcode, - findByTrainUid, -}; - -/* Internal Functions, not to be exported */ - -/* Accepts the 'stops' array from a db query and produces an - array of only public stops as TIPLOCs. */ -async function getPublicStops(data: Stop[]): Promise { - let tiplocList = []; - for (const publicStop in data) { - if (data[publicStop]["isPublic"]) { - tiplocList.push(data[publicStop]["tiploc"]); - } - } - return tiplocList; -} - -/* Takes a single days data from a headcode query and requeries - using the trainUid, required to ensure any cancellations are - accounted for */ -async function parseTrains(data: TrainServices[]): Promise { - let trainUids: string[] = []; - for (const i of data) { - const trainUid = i["trainUid"]; - if (!trainUids.includes(trainUid)) { - trainUids.push(trainUid); - } - } - let parsedData: TrainServices[] = []; - for (const i in trainUids) { - const result: TrainServices | null = await findByTrainUid(trainUids[i]); - if (result) { - parsedData.push(result); - } - } - return parsedData; -} - -// Filters services based on their STP Indicator -async function filterServices(data: Service[]): Promise { - let stpIndicators = {}, - filteredServices = []; - for (const serviceDetail of data) { - const trainUid = serviceDetail["trainUid"]; - const stpIndicator = serviceDetail["stpIndicator"]; - if (!stpIndicators[trainUid]) { - stpIndicators[trainUid] = { - hasC: false, - hasN: false, - hasO: false, - hasP: false, - }; - } - if (stpIndicator === "C") { - stpIndicators[trainUid].hasC = true; - } - if (stpIndicator === "N") { - stpIndicators[trainUid].hasN = true; - } - if (stpIndicator === "O") { - stpIndicators[trainUid].hasO = true; - } - if (stpIndicator === "P") { - stpIndicators[trainUid].hasP = true; - } - } - - for (const serviceDetail of data) { - const trainUid = serviceDetail["trainUid"]; - const thisStpIndicators = stpIndicators[trainUid]; - const stpIndicator = serviceDetail["stpIndicator"]; - - if (stpIndicator === "C") { - break; - } - if (stpIndicator === "N" && !thisStpIndicators.hasC) { - filteredServices.push(serviceDetail); - } else if ( - stpIndicator === "O" && - !thisStpIndicators.hasC && - !thisStpIndicators.hasN - ) { - filteredServices.push(serviceDetail); - } else if ( - stpIndicator === "P" && - !thisStpIndicators.hasC && - !thisStpIndicators.hasN && - !thisStpIndicators.hasO - ) { - filteredServices.push(serviceDetail); - } - } - return filteredServices; -} diff --git a/src/services/ldb.services.js b/src/services/ldb.services.js index 5b2762f..98cc786 100644 --- a/src/services/ldb.services.js +++ b/src/services/ldb.services.js @@ -8,7 +8,7 @@ const db = require("../services/dbAccess.services"); import { logger } from "../utils/logger.utils"; import { transform as staffStationTransform } from "../utils/processors/ldb/staffStation"; -import { msgCodes } from "../configs/errorCodes.configs"; + const ldbKey = process.env.OWL_LDB_KEY; const ldbsvKey = process.env.OWL_LDB_SVKEY; @@ -69,14 +69,18 @@ async function arrDepBoardStaff(CRS) { }; const api = new ldb(ldbsvKey, true); console.time(`Fetch Staff LDB for ${CRS.toUpperCase()}`); - const result = await api.call( - "GetArrivalDepartureBoardByCRS", - options, - false, - false - ); - console.log("\n\n\nORIGINAL DATA"); - console.log("\n" + JSON.stringify(result) + "\n\n\n"); + let result + try { + result = await staffApiCallRetry( + api, + "GetArrivalDepartureBoardByCRS", + options, + 5, + ); + } catch (err) { + logger.error(err, "Error fetching board data"); + return {obStatus: "Error", obMsg: "Error fetching data from National Rail", data: null} + } console.timeEnd(`Fetch Staff LDB for ${CRS.toUpperCase()}`); try { const _staffLdb = staffStationTransform(result); @@ -128,6 +132,24 @@ async function getServicesByOther(id) { } } +async function staffApiCallRetry(api, method, options, retries) { + for (let i=0; i < retries; i++) { + try { + return await api.call(method, options, false, false); + } catch (err) { + if (err.code === 'ENOTFOUND') { + logger.warn(err, "DNS ERR") + if (i < retries - 1) { + logger.debug('Retrying API Call') + continue; + } + } + throw err; + } + } + throw new Error("Max retries exceeded"); +} + async function getReasonCodeList() { logger.debug("ldbService.getReasonCodeList: Fetching reason code list"); try {