Add retry to LDB Staff lookup
Signed-off-by: Fred Boniface <fred@fjla.uk>
This commit is contained in:
parent
dad9f46d86
commit
e7b8208edf
@ -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<TrainServices[]> {
|
|
||||||
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<TrainServices | null> {
|
|
||||||
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<string[]> {
|
|
||||||
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<TrainServices[]> {
|
|
||||||
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<TrainServices[]> {
|
|
||||||
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;
|
|
||||||
}
|
|
@ -8,7 +8,7 @@ const db = require("../services/dbAccess.services");
|
|||||||
import { logger } from "../utils/logger.utils";
|
import { logger } from "../utils/logger.utils";
|
||||||
|
|
||||||
import { transform as staffStationTransform } from "../utils/processors/ldb/staffStation";
|
import { transform as staffStationTransform } from "../utils/processors/ldb/staffStation";
|
||||||
import { msgCodes } from "../configs/errorCodes.configs";
|
|
||||||
|
|
||||||
const ldbKey = process.env.OWL_LDB_KEY;
|
const ldbKey = process.env.OWL_LDB_KEY;
|
||||||
const ldbsvKey = process.env.OWL_LDB_SVKEY;
|
const ldbsvKey = process.env.OWL_LDB_SVKEY;
|
||||||
@ -69,14 +69,18 @@ async function arrDepBoardStaff(CRS) {
|
|||||||
};
|
};
|
||||||
const api = new ldb(ldbsvKey, true);
|
const api = new ldb(ldbsvKey, true);
|
||||||
console.time(`Fetch Staff LDB for ${CRS.toUpperCase()}`);
|
console.time(`Fetch Staff LDB for ${CRS.toUpperCase()}`);
|
||||||
const result = await api.call(
|
let result
|
||||||
|
try {
|
||||||
|
result = await staffApiCallRetry(
|
||||||
|
api,
|
||||||
"GetArrivalDepartureBoardByCRS",
|
"GetArrivalDepartureBoardByCRS",
|
||||||
options,
|
options,
|
||||||
false,
|
5,
|
||||||
false
|
|
||||||
);
|
);
|
||||||
console.log("\n\n\nORIGINAL DATA");
|
} catch (err) {
|
||||||
console.log("\n" + JSON.stringify(result) + "\n\n\n");
|
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()}`);
|
console.timeEnd(`Fetch Staff LDB for ${CRS.toUpperCase()}`);
|
||||||
try {
|
try {
|
||||||
const _staffLdb = staffStationTransform(result);
|
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() {
|
async function getReasonCodeList() {
|
||||||
logger.debug("ldbService.getReasonCodeList: Fetching reason code list");
|
logger.debug("ldbService.getReasonCodeList: Fetching reason code list");
|
||||||
try {
|
try {
|
||||||
|
Loading…
Reference in New Issue
Block a user