Refactor Redis, Postgres, and Clickhouse connection check methods

This commit is contained in:
Simon Larsen
2024-04-24 13:03:07 +01:00
parent 8b0f23e18f
commit 32c78f24e9
11 changed files with 2055 additions and 1899 deletions

View File

@@ -16,65 +16,74 @@ import StatusServiceHandler from './Service/Status';
import DataTypeServiceHandler from './Service/DataType';
import Dictionary from 'Common/Types/Dictionary';
import { StaticPath } from './Utils/Config';
import FeatureSet from 'CommonServer/Types/FeatureSet';
const init: VoidFunction = () => {
const ResourceDictionary: Dictionary<ModelDocumentation> =
ResourceUtil.getResourceDictionaryByPath();
const APIReferenceFeatureSet: FeatureSet = {
init: async (): Promise<void> => {
const ResourceDictionary: Dictionary<ModelDocumentation> =
ResourceUtil.getResourceDictionaryByPath();
const app: ExpressApplication = Express.getExpressApp();
const app: ExpressApplication = Express.getExpressApp();
app.use('/reference', ExpressStatic(StaticPath, { maxAge: 2592000 }));
app.use('/reference', ExpressStatic(StaticPath, { maxAge: 2592000 }));
// Index page
app.get(['/reference'], (_req: ExpressRequest, res: ExpressResponse) => {
return res.redirect('/reference/introduction');
});
// Index page
app.get(
['/reference'],
(_req: ExpressRequest, res: ExpressResponse) => {
return res.redirect('/reference/introduction');
}
);
app.get(
['/reference/page-not-found'],
(req: ExpressRequest, res: ExpressResponse) => {
return PageNotFoundServiceHandler.executeResponse(req, res);
}
);
// All Pages
app.get(
['/reference/:page'],
(req: ExpressRequest, res: ExpressResponse) => {
const page: string | undefined = req.params['page'];
if (!page) {
app.get(
['/reference/page-not-found'],
(req: ExpressRequest, res: ExpressResponse) => {
return PageNotFoundServiceHandler.executeResponse(req, res);
}
);
const currentResource: ModelDocumentation | undefined =
ResourceDictionary[page];
// All Pages
app.get(
['/reference/:page'],
(req: ExpressRequest, res: ExpressResponse) => {
const page: string | undefined = req.params['page'];
if (req.params['page'] === 'permissions') {
return PermissionServiceHandler.executeResponse(req, res);
} else if (req.params['page'] === 'authentication') {
return AuthenticationServiceHandler.executeResponse(req, res);
} else if (req.params['page'] === 'pagination') {
return PaginationServiceHandler.executeResponse(req, res);
} else if (req.params['page'] === 'errors') {
return ErrorServiceHandler.executeResponse(req, res);
} else if (req.params['page'] === 'introduction') {
return IntroductionServiceHandler.executeResponse(req, res);
} else if (req.params['page'] === 'status') {
return StatusServiceHandler.executeResponse(req, res);
} else if (req.params['page'] === 'data-types') {
return DataTypeServiceHandler.executeResponse(req, res);
} else if (currentResource) {
return ModelServiceHandler.executeResponse(req, res);
if (!page) {
return PageNotFoundServiceHandler.executeResponse(req, res);
}
const currentResource: ModelDocumentation | undefined =
ResourceDictionary[page];
if (req.params['page'] === 'permissions') {
return PermissionServiceHandler.executeResponse(req, res);
} else if (req.params['page'] === 'authentication') {
return AuthenticationServiceHandler.executeResponse(
req,
res
);
} else if (req.params['page'] === 'pagination') {
return PaginationServiceHandler.executeResponse(req, res);
} else if (req.params['page'] === 'errors') {
return ErrorServiceHandler.executeResponse(req, res);
} else if (req.params['page'] === 'introduction') {
return IntroductionServiceHandler.executeResponse(req, res);
} else if (req.params['page'] === 'status') {
return StatusServiceHandler.executeResponse(req, res);
} else if (req.params['page'] === 'data-types') {
return DataTypeServiceHandler.executeResponse(req, res);
} else if (currentResource) {
return ModelServiceHandler.executeResponse(req, res);
}
// page not found
return PageNotFoundServiceHandler.executeResponse(req, res);
}
// page not found
return PageNotFoundServiceHandler.executeResponse(req, res);
}
);
);
app.get('/reference/*', (req: ExpressRequest, res: ExpressResponse) => {
return PageNotFoundServiceHandler.executeResponse(req, res);
});
app.get('/reference/*', (req: ExpressRequest, res: ExpressResponse) => {
return PageNotFoundServiceHandler.executeResponse(req, res);
});
},
};
export default { init };
export default APIReferenceFeatureSet;

File diff suppressed because it is too large Load Diff

View File

@@ -10,79 +10,84 @@ import DocsNav, { NavGroup, NavLink } from './Utils/Nav';
import LocalFile from 'CommonServer/Utils/LocalFile';
import DocsRender from './Utils/Render';
import logger from 'CommonServer/Utils/Logger';
import FeatureSet from 'CommonServer/Types/FeatureSet';
const init: VoidFunction = (): void => {
const app: ExpressApplication = Express.getExpressApp();
const DocsFeatureSet: FeatureSet = {
init: async (): Promise<void> => {
const app: ExpressApplication = Express.getExpressApp();
app.get('/docs', (_req: ExpressRequest, res: ExpressResponse) => {
res.redirect('/docs/introduction/getting-started');
});
app.get('/docs', (_req: ExpressRequest, res: ExpressResponse) => {
res.redirect('/docs/introduction/getting-started');
});
app.get(
'/docs/:categorypath/:pagepath',
async (_req: ExpressRequest, res: ExpressResponse) => {
try {
const fullPath: string =
`${_req.params['categorypath']}/${_req.params['pagepath']}`.toLowerCase();
app.get(
'/docs/:categorypath/:pagepath',
async (_req: ExpressRequest, res: ExpressResponse) => {
try {
const fullPath: string =
`${_req.params['categorypath']}/${_req.params['pagepath']}`.toLowerCase();
// read file from Content folder.
let contentInMarkdown: string = await LocalFile.read(
`${ContentPath}/${fullPath}.md`
);
// read file from Content folder.
let contentInMarkdown: string = await LocalFile.read(
`${ContentPath}/${fullPath}.md`
);
// remove first line from content because we dont want to show title in content. Title is already in nav.
// remove first line from content because we dont want to show title in content. Title is already in nav.
contentInMarkdown = contentInMarkdown
.split('\n')
.slice(1)
.join('\n');
contentInMarkdown = contentInMarkdown
.split('\n')
.slice(1)
.join('\n');
const renderedContent: string = await DocsRender.render(
contentInMarkdown
);
const renderedContent: string = await DocsRender.render(
contentInMarkdown
);
const currentCategory: NavGroup | undefined = DocsNav.find(
(category: NavGroup) => {
return category.links.find((link: NavLink) => {
const currentCategory: NavGroup | undefined = DocsNav.find(
(category: NavGroup) => {
return category.links.find((link: NavLink) => {
return link.url
.toLocaleLowerCase()
.includes(fullPath);
});
}
);
const currrentNavLink: NavLink | undefined =
currentCategory?.links.find((link: NavLink) => {
return link.url
.toLocaleLowerCase()
.includes(fullPath);
});
if (!currentCategory || !currrentNavLink) {
// render not found.
res.status(404);
return res.render(`${ViewsPath}/NotFound`, {
nav: DocsNav,
});
}
);
const currrentNavLink: NavLink | undefined =
currentCategory?.links.find((link: NavLink) => {
return link.url.toLocaleLowerCase().includes(fullPath);
res.render(`${ViewsPath}/Index`, {
nav: DocsNav,
content: renderedContent,
category: currentCategory,
link: currrentNavLink,
githubPath: fullPath,
});
if (!currentCategory || !currrentNavLink) {
// render not found.
res.status(404);
return res.render(`${ViewsPath}/NotFound`, {
} catch (err) {
logger.error(err);
res.status(500);
return res.render(`${ViewsPath}/ServerError`, {
nav: DocsNav,
});
}
res.render(`${ViewsPath}/Index`, {
nav: DocsNav,
content: renderedContent,
category: currentCategory,
link: currrentNavLink,
githubPath: fullPath,
});
} catch (err) {
logger.error(err);
res.status(500);
return res.render(`${ViewsPath}/ServerError`, {
nav: DocsNav,
});
}
}
);
);
app.use('/docs/static', ExpressStatic(StaticPath));
app.use('/docs/static', ExpressStatic(StaticPath));
},
};
export default { init };
export default DocsFeatureSet;

File diff suppressed because it is too large Load Diff

View File

@@ -5,25 +5,27 @@ import SsoAPI from './API/SSO';
import ResellerAPI from './API/Reseller';
import StatusPageSsoAPI from './API/StatusPageSSO';
import StatusPageAuthenticationAPI from './API/StatusPageAuthentication';
import { VoidFunction } from 'Common/Types/FunctionTypes';
import FeatureSet from 'CommonServer/Types/FeatureSet';
const init: VoidFunction = () => {
const app: ExpressApplication = Express.getExpressApp();
const IdentityFeatureSet: FeatureSet = {
init: async (): Promise<void> => {
const app: ExpressApplication = Express.getExpressApp();
const APP_NAME: string = 'api/identity';
const APP_NAME: string = 'api/identity';
app.use([`/${APP_NAME}`, '/'], AuthenticationAPI);
app.use([`/${APP_NAME}`, '/'], AuthenticationAPI);
app.use([`/${APP_NAME}`, '/'], ResellerAPI);
app.use([`/${APP_NAME}`, '/'], ResellerAPI);
app.use([`/${APP_NAME}`, '/'], SsoAPI);
app.use([`/${APP_NAME}`, '/'], SsoAPI);
app.use([`/${APP_NAME}`, '/'], StatusPageSsoAPI);
app.use([`/${APP_NAME}`, '/'], StatusPageSsoAPI);
app.use(
[`/${APP_NAME}/status-page`, '/status-page'],
StatusPageAuthenticationAPI
);
app.use(
[`/${APP_NAME}/status-page`, '/status-page'],
StatusPageAuthenticationAPI
);
},
};
export default { init };
export default IdentityFeatureSet;

View File

@@ -7,15 +7,18 @@ import SmsAPI from './API/SMS';
import CallAPI from './API/Call';
import SMTPConfigAPI from './API/SMTPConfig';
import './Utils/Handlebars';
import FeatureSet from 'CommonServer/Types/FeatureSet';
const init: VoidFunction = () => {
const APP_NAME: string = 'api/notification';
const app: ExpressApplication = Express.getExpressApp();
const NotificationFeatureSet: FeatureSet = {
init: async (): Promise<void> => {
const APP_NAME: string = 'api/notification';
const app: ExpressApplication = Express.getExpressApp();
app.use([`/${APP_NAME}/email`, '/email'], MailAPI);
app.use([`/${APP_NAME}/sms`, '/sms'], SmsAPI);
app.use([`/${APP_NAME}/call`, '/call'], CallAPI);
app.use([`/${APP_NAME}/smtp-config`, '/smtp-config'], SMTPConfigAPI);
app.use([`/${APP_NAME}/email`, '/email'], MailAPI);
app.use([`/${APP_NAME}/sms`, '/sms'], SmsAPI);
app.use([`/${APP_NAME}/call`, '/call'], CallAPI);
app.use([`/${APP_NAME}/smtp-config`, '/smtp-config'], SMTPConfigAPI);
},
};
export default { init };
export default NotificationFeatureSet;

View File

@@ -13,11 +13,14 @@ export default class ComponentCodeAPI {
public constructor() {
this.router = Express.getRouter();
}
public init(): void {
// init all component code.
/// Get all the components.
for (const key in Components) {
const ComponentCode: ComponentCode | undefined = Components[key];
if (ComponentCode instanceof TriggerCode) {
const instance: TriggerCode = ComponentCode;
instance

View File

@@ -5,7 +5,7 @@ import Express, {
} from 'CommonServer/Utils/Express';
import logger from 'CommonServer/Utils/Logger';
import ManualAPI from './API/Manual';
import ComponentCode from './API/ComponentCode';
import ComponentCodeAPI from './API/ComponentCode';
import { QueueJob, QueueName } from 'CommonServer/Infrastructure/Queue';
import QueueWorker from 'CommonServer/Infrastructure/QueueWorker';
import RunWorkflow from './Services/RunWorkflow';
@@ -16,27 +16,30 @@ import FeatureSet from 'CommonServer/Types/FeatureSet';
const APP_NAME: string = 'api/workflow';
const app: ExpressApplication = Express.getExpressApp();
app.use(`/${APP_NAME}/manual`, new ManualAPI().router);
app.use(`/${APP_NAME}`, new WorkflowAPI().router);
app.get(
`/${APP_NAME}/docs/:componentName`,
(req: ExpressRequest, res: ExpressResponse) => {
res.sendFile(
'/usr/src/app/FeatureSet/Workflow/Docs/ComponentDocumentation/' +
req.params['componentName']
);
}
);
app.use(`/${APP_NAME}`, new ComponentCode().router);
const WorkflowFeatureSet: FeatureSet = {
init: async (): Promise<void> => {
try {
const componentCodeAPI: ComponentCodeAPI = new ComponentCodeAPI();
componentCodeAPI.init();
const app: ExpressApplication = Express.getExpressApp();
app.use(`/${APP_NAME}/manual`, new ManualAPI().router);
app.use(`/${APP_NAME}`, new WorkflowAPI().router);
app.get(
`/${APP_NAME}/docs/:componentName`,
(req: ExpressRequest, res: ExpressResponse) => {
res.sendFile(
'/usr/src/app/FeatureSet/Workflow/Docs/ComponentDocumentation/' +
req.params['componentName']
);
}
);
app.use(`/${APP_NAME}`, componentCodeAPI.router);
// Job process.
QueueWorker.getWorker(
QueueName.Workflow,

View File

@@ -98,6 +98,32 @@ export default class ClickhouseDatabase {
this.dataSource = null;
}
}
public async checkConnnectionStatus(): Promise<boolean> {
// Ping clickhouse to check if the connection is still alive
try {
const result: PingResult | undefined =
await this.getDataSource()?.ping();
if (!result) {
throw new DatabaseNotConnectedException(
'Clickhouse Database is not connected'
);
}
if (result?.success === false) {
throw new DatabaseNotConnectedException(
'Clickhouse Database is not connected'
);
}
return true;
} catch (err) {
logger.error('Clickhouse Connection Lost');
logger.error(err);
return false;
}
}
}
export const ClickhouseAppInstance: ClickhouseDatabase =

View File

@@ -71,6 +71,23 @@ export default class Database {
this.dataSource = null;
}
}
public async checkConnnectionStatus(): Promise<boolean> {
// check popstgres connection to see if it is still alive
try {
await this.dataSource?.query(
`SELECT COUNT(key) FROM ${
this.getDatasourceOptions().database
}.GreenlockChallenge`
); // this is a dummy query to check if the connection is still alive
return true;
} catch (err) {
logger.error('Postgres Connection Lost');
logger.error(err);
return false;
}
}
}
export const PostgresAppInstance: Database = new Database();

View File

@@ -122,4 +122,16 @@ export default abstract class Redis {
this.client = null;
}
}
public static async checkConnnectionStatus(): Promise<boolean> {
// Ping redis to check if the connection is still alive
try {
await this.client?.ping();
return true;
} catch (err) {
logger.error('Redis Connection Lost');
logger.error(err);
return false;
}
}
}