refactor: rename email-server-worker to email-worker
Rename directory from email-server-worker to email-worker for clarity and brevity. Update all references in CLAUDE.md documentation.
This commit is contained in:
81
email-worker/src/routes/errorRouter.ts
Normal file
81
email-worker/src/routes/errorRouter.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
import { ErrorRequestHandler, Request, Response } from "express";
|
||||
import createHttpError, { HttpError } from "http-errors";
|
||||
import { createLogger } from '../lib/logger';
|
||||
import { NgitLocals } from "../types/NgitLocals";
|
||||
import { failedRequestCounter } from "../lib/metricsCounters";
|
||||
import { SupportedRoutes } from "../types/enums/SupportedRoutes";
|
||||
|
||||
const consoleLog = createLogger("server:server");
|
||||
|
||||
/**
|
||||
* Router koji se zadnji poziva, a koji sastavlja odgovor u slučaju greške
|
||||
* @param err
|
||||
* @param req
|
||||
* @param res
|
||||
* @param next
|
||||
*/
|
||||
export const errorRouter:ErrorRequestHandler = async (err:HttpError, req, res, next) => {
|
||||
|
||||
const requestPath = req.path as SupportedRoutes;
|
||||
|
||||
// kako je ovaj error handler dosta složen, moguće je da negdje baci grešku
|
||||
// > zato je zamotan u try-catch
|
||||
// > na taj način osiguravam da neće srušiti cijeli proces
|
||||
try {
|
||||
|
||||
let { name:errorLogName, message:errorLogText } = err;
|
||||
let responseBody:string = "";
|
||||
|
||||
switch(err.status) {
|
||||
case 400:
|
||||
responseBody = 'bad request';
|
||||
break;
|
||||
case 401:
|
||||
responseBody = 'unauthorized';
|
||||
break;
|
||||
case 403:
|
||||
responseBody = 'forbidden';
|
||||
break;
|
||||
case 404:
|
||||
consoleLog(`page not found ${req.method} ${requestPath}`)
|
||||
responseBody = 'page not found';
|
||||
errorLogText = `page ${requestPath} not found`;
|
||||
break;
|
||||
case 500:
|
||||
responseBody = "internal server error";
|
||||
errorLogText = err.message;
|
||||
break;
|
||||
default:
|
||||
responseBody = err.name;
|
||||
errorLogText = `err.status=${err.status};err.name=${err.name};err.message=${err.message}`;
|
||||
}
|
||||
|
||||
consoleLog(`${errorLogName}:${errorLogText}`);
|
||||
|
||||
// `headersSent` će biti TRUE ako je router kod kojeg se dogodila greška već poslao header-e
|
||||
// > ako ih probam ponovo postaviti, to će baciti grešku ... a to ovdje mogu izbjeći
|
||||
if(!res.headersSent) {
|
||||
res.status(err.status);
|
||||
res.setHeader('Content-Type', "text/html");
|
||||
res.end(responseBody);
|
||||
} else {
|
||||
// AKO nije pozvan `end` - pozovi ga i završi obradu zahtjeva
|
||||
// ... u suprotnom će konekcija ostati otvorena do timeout-a
|
||||
if(!res.writableEnded) {
|
||||
res.end();
|
||||
}
|
||||
}
|
||||
|
||||
} catch(ex:any) {
|
||||
// ovu grešku će obraditi `finalErrorRouter`
|
||||
next(createHttpError(500, ex));
|
||||
}
|
||||
|
||||
// ne mogu dopustiti da prometheus client sruši server
|
||||
try {
|
||||
failedRequestCounter.inc({ path: requestPath, status: err.status });
|
||||
(res.locals as NgitLocals).stopPrometheusTimer({ path: req.path, status: err.status });
|
||||
} catch(ex:any) {
|
||||
console.error(ex);
|
||||
}
|
||||
};
|
||||
34
email-worker/src/routes/finalErrorRouter.ts
Normal file
34
email-worker/src/routes/finalErrorRouter.ts
Normal file
@@ -0,0 +1,34 @@
|
||||
import { ErrorRequestHandler, Request, Response } from "express";
|
||||
import { HttpError } from "http-errors";
|
||||
import { createLogger } from '../lib/logger';
|
||||
import { NgitLocals } from "../types/NgitLocals";
|
||||
|
||||
const consoleLog = createLogger("server:server");
|
||||
|
||||
/**
|
||||
* Router koji se izvršava u slučaju grube greške koja nije obrađena nigdje prije
|
||||
* @param err error objekt
|
||||
* @param req express request
|
||||
* @param res express response
|
||||
* @param next
|
||||
*/
|
||||
export const finalErrorRouter:ErrorRequestHandler = async (err:HttpError, req, res, next) => {
|
||||
|
||||
const errorLogText:string = JSON.stringify({ message:err.message, name:err.name, stack:err.stack });
|
||||
|
||||
consoleLog(`Server Error ${err.status}\n${errorLogText}`);
|
||||
|
||||
// `headersSent` će biti TRUE ako je router kod kojeg se dogodila greška već poslao header-e
|
||||
// > ako ih probam ponovo postaviti, to će baciti grešku i u ovom slučaju SRUŠITI SERVER - to ne smijemo dopustiti
|
||||
if(!res.headersSent) {
|
||||
res.status(err.status);
|
||||
res.setHeader('Content-Type', "text/html");
|
||||
res.end(`unhandled server error`);
|
||||
} else {
|
||||
// AKO nije pozvan `end` - pozovi ga i završi obradu zahtjeva
|
||||
// ... u suprotnom će konekcija ostati otvorena do timeout-a
|
||||
if(!res.writableEnded) {
|
||||
res.end();
|
||||
}
|
||||
}
|
||||
};
|
||||
35
email-worker/src/routes/healthcheckRouter.ts
Normal file
35
email-worker/src/routes/healthcheckRouter.ts
Normal file
@@ -0,0 +1,35 @@
|
||||
import { RequestHandler, Router } from "express";
|
||||
import { workerRunnerInfo } from "../workRunner";
|
||||
import { coalesce } from "../lib/initTools";
|
||||
|
||||
const PULL_INTERVAL = parseInt(coalesce(process.env.PULL_INTERVAL, "10000"));
|
||||
|
||||
/** Maximum time between two worker jobs */
|
||||
const MAX_WORKER_LATENCY = PULL_INTERVAL * 2.5;
|
||||
|
||||
/**
|
||||
* Router koji se izvršava u slučaju grube greške koja nije obrađena nigdje prije
|
||||
* @param req express request
|
||||
* @param res express response
|
||||
* @param next
|
||||
*/
|
||||
export const healthcheckRouter:RequestHandler = async (req, res, next) => {
|
||||
const workerLatency = Date.now() - workerRunnerInfo.lastWorkTime;
|
||||
|
||||
if(workerLatency > MAX_WORKER_LATENCY) {
|
||||
const msg = `No work done in ${workerLatency}ms. Last worker status = "${workerRunnerInfo.status}"`;
|
||||
|
||||
console.warn(msg)
|
||||
|
||||
res.status(500);
|
||||
res.setHeader('Content-Type', 'text/plain');
|
||||
res.end(msg);
|
||||
} else {
|
||||
res.status(200);
|
||||
res.setHeader('Content-Type', 'text/plain');
|
||||
res.end('OK');
|
||||
}
|
||||
};
|
||||
|
||||
export const pingRouter = Router();
|
||||
pingRouter.get('/', healthcheckRouter);
|
||||
19
email-worker/src/routes/metricsRouter.ts
Normal file
19
email-worker/src/routes/metricsRouter.ts
Normal file
@@ -0,0 +1,19 @@
|
||||
import { Router, NextFunction, Request, Response } from "express";
|
||||
import createError from 'http-errors';
|
||||
import { register } from 'prom-client';
|
||||
import { createLogger } from '../lib/logger';
|
||||
|
||||
const logger = createLogger("server:metrics");
|
||||
|
||||
export const metricsRouter = Router();
|
||||
|
||||
metricsRouter.get('/', async (req:Request, res:Response, next:NextFunction) => {
|
||||
// ne mogu dopustiti da prometheus client sruši server
|
||||
try {
|
||||
logger(`⚡️[server]: GET /metrics`);
|
||||
res.set('Content-Type', register.contentType);
|
||||
res.end(await register.metrics());
|
||||
} catch(ex:any) {
|
||||
next(createError(500, (ex as Error).message));
|
||||
}
|
||||
});
|
||||
16
email-worker/src/routes/pingRouter.ts
Normal file
16
email-worker/src/routes/pingRouter.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
import { RequestHandler, Router } from "express";
|
||||
|
||||
/**
|
||||
* Router koji se izvršava u slučaju grube greške koja nije obrađena nigdje prije
|
||||
* @param req express request
|
||||
* @param res express response
|
||||
* @param next
|
||||
*/
|
||||
export const pingRequestHandler:RequestHandler = async (req, res, next) => {
|
||||
res.status(200);
|
||||
res.setHeader('Content-Type', 'text/plain');
|
||||
res.end('PONG');
|
||||
};
|
||||
|
||||
export const pingRouter = Router();
|
||||
pingRouter.get('/', pingRequestHandler);
|
||||
Reference in New Issue
Block a user