diff --git a/__tests__/unit/bin/start.ts b/__tests__/unit/bin/start.ts deleted file mode 100644 index 2eda8d2..0000000 --- a/__tests__/unit/bin/start.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { start, shutdown } from "../../../src/bin/start"; - -jest.mock("register-server-handlers"); -jest.mock("sourced-repo-typeorm", () => { - return { - Repository: jest.fn(), - persistenceLayer: { - connect: jest.fn(() => Promise.resolve(true)), - disconnect: jest.fn(() => Promise.resolve(true)), - }, - }; -}); - -jest.mock("express", () => { - const m: any = { - __esModule: true, - Router: jest.fn(() => ({ - use: jest.fn(), - get: jest.fn(), - post: jest.fn(), - })), - }; - - m.default = jest.fn(() => ({ - use: jest.fn(), - get: jest.fn(), - post: jest.fn(), - listen: jest.fn(() => ({ - close: jest.fn(), - })), - })); - m.default.urlencoded = jest.fn(); - m.default.json = jest.fn(); - - return m; -}); - -jest.spyOn(process, "exit").mockImplementation(() => { - return undefined as never; -}); - -describe("bin/start.ts", () => { - it("should start our service", async () => { - const express = await (await import("express")).default; - const server = express(); - const { registerHandlers } = await import("register-server-handlers"); - await start(server, "./handlers"); - expect(registerHandlers).toBeCalled(); - }); - - it("should throw an error if it cant connect to persistenceLayer", async () => { - const { persistenceLayer } = await import("sourced-repo-typeorm"); - persistenceLayer.connect = jest.fn( - () => - new Promise((resolve, reject) => { - reject(new Error("PSQL Error")); - }) - ); - - const express = await (await import("express")).default; - const server = express(); - await start(server, "./handlers"); - - // expect(server.log.error).toBeCalled(); - expect(process.exit).toBeCalledWith(1); - }); - - it("should shutdown server and persistencelayer", async () => { - const { persistenceLayer } = await import("sourced-repo-typeorm"); - const server = { - log: { - info: jest.fn(), - }, - close: jest.fn(() => Promise.resolve(true)), - }; - await shutdown(server)(); - - expect(server.close).toBeCalled(); - expect(persistenceLayer.disconnect).toBeCalled(); - }); -}); diff --git a/__tests__/unit/lib/healthcheck.ts b/__tests__/unit/lib/healthcheck.ts deleted file mode 100644 index 4e82050..0000000 --- a/__tests__/unit/lib/healthcheck.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { healthcheck } from "../../../src/lib/healthcheck"; - -describe("healthcheck", () => { - it("should respond with 200", () => { - const send = jest.fn(); - const json = jest.fn(); - const reply = { - status: jest.fn(() => ({ - send, - json, - })), - }; - healthcheck({}, reply); - expect(reply.status).toBeCalledWith(200); - expect(send).toBeCalledWith("ok"); - }); -}); diff --git a/package-lock.json b/package-lock.json index 05e164a..1ecbc15 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,11 +12,9 @@ "axios": "1.1.3", "axios-retry": "3.3.1", "debug": "4.3.4", - "express": "4.18.2", - "express-pino-logger": "7.0.0", + "knative-microservice": "1.0.2", "knativebus": "2.3.17", "pino": "8.7.0", - "register-server-handlers": "4.2.4", "sourced": "4.0.6", "sourced-queued-repo-promise": "1.1.0", "sourced-repo-typeorm": "3.2.7", @@ -4933,6 +4931,16 @@ "node": ">=6" } }, + "node_modules/knative-microservice": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/knative-microservice/-/knative-microservice-1.0.2.tgz", + "integrity": "sha512-fI02NLu7rzAdyVQp6AD7gxUf4OyKZJza+vVOsZmaif4/PIqp2HjZ8GbDTAaWRTquZhcl56ISg2uVPsJiwOksTw==", + "dependencies": { + "express": "^4.18.2", + "express-pino-logger": "^7.0.0", + "register-server-handlers": "^4.2.4" + } + }, "node_modules/knativebus": { "version": "2.3.17", "resolved": "https://registry.npmjs.org/knativebus/-/knativebus-2.3.17.tgz", @@ -11637,6 +11645,16 @@ "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", "dev": true }, + "knative-microservice": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/knative-microservice/-/knative-microservice-1.0.2.tgz", + "integrity": "sha512-fI02NLu7rzAdyVQp6AD7gxUf4OyKZJza+vVOsZmaif4/PIqp2HjZ8GbDTAaWRTquZhcl56ISg2uVPsJiwOksTw==", + "requires": { + "express": "^4.18.2", + "express-pino-logger": "^7.0.0", + "register-server-handlers": "^4.2.4" + } + }, "knativebus": { "version": "2.3.17", "resolved": "https://registry.npmjs.org/knativebus/-/knativebus-2.3.17.tgz", diff --git a/package.json b/package.json index 52cb7f5..18f426e 100644 --- a/package.json +++ b/package.json @@ -20,11 +20,9 @@ "axios": "1.1.3", "axios-retry": "3.3.1", "debug": "4.3.4", - "express": "4.18.2", - "express-pino-logger": "7.0.0", + "knative-microservice": "1.0.2", "knativebus": "2.3.17", "pino": "8.7.0", - "register-server-handlers": "4.2.4", "sourced": "4.0.6", "sourced-queued-repo-promise": "1.1.0", "sourced-repo-typeorm": "3.2.7", diff --git a/src/bin/start.ts b/src/bin/start.ts index b2b062a..737ac12 100644 --- a/src/bin/start.ts +++ b/src/bin/start.ts @@ -1,33 +1,15 @@ import path from "path"; -import express, { Router } from "express"; import pino from "pino"; -import pinoLoggerMiddleware from "express-pino-logger"; import { persistenceLayer } from "sourced-repo-typeorm"; -import { registerHandlers } from "register-server-handlers"; import { config } from "../config.js"; -import { healthcheck } from "../lib/healthcheck.js"; +import { microservice } from "knative-microservice"; const { port, sourced, handlerBasePath } = config; const handlersPath = path.resolve(process.cwd(), handlerBasePath, "handlers"); -const logger = pino(); -const pinoLogger = pinoLoggerMiddleware({ logger }); -const server = express(); +export const start = async () => { + const logger = pino(); -const healthRouter = Router(); -const appRouter = Router(); - -let listeningServer; - -// parse application/x-www-form-urlencoded -server.use(express.urlencoded({ extended: false })); -// parse application/json -server.use(express.json({ limit: "50mb" })); - -// enable request logging -appRouter.use(pinoLogger); - -export const start = async (server, handlersPath: string) => { const connectionOptions = { type: "postgres" as const, url: sourced.psql.url, @@ -39,6 +21,7 @@ export const start = async (server, handlersPath: string) => { }, }, }; + logger.info({ msg: "⏳ connecting to psql", sync: connectionOptions.synchronize, @@ -52,60 +35,20 @@ export const start = async (server, handlersPath: string) => { } logger.info("✅ connected to psql"); - healthRouter.get("/", healthcheck); - server.use("/health", healthRouter); - - logger.info(`⏳ registering server handlers from ${handlersPath}`); - // register handlers as HTTP Post handlers - await registerHandlers({ - server: appRouter, - path: handlersPath, - handlerOptions: { - sync: config.enableSyncSendToDenormalizer, - enableEventPublishing: config.enableEventPublishing, - }, - }); - - logger.info( - `⏳ registering server cloud event handlers from ${handlersPath}` - ); - // register handlers as KNative Cloud Event Handlers - await registerHandlers({ - server: appRouter, - path: handlersPath, - cloudevents: true, - serverPath: "/cloudevent/", - handlerOptions: { - sync: false, - enableEventPublishing: config.enableEventPublishing, + const { server, shutdown, onListen } = await microservice({ + handlers: { + path: handlersPath, + options: { + enableSyncSendToDenormalizer: config.enableSyncSendToDenormalizer, + enableEventPublishing: config.enableEventPublishing, + }, }, + logger, }); - server.use("/", appRouter); - - logger.info(`✅ handlers registered`); + server.listen(port, onListen(port)); - listeningServer = server.listen(port, onListen(port)); + process.on("SIGTERM", shutdown(persistenceLayer)); }; -const onListen = (port) => { - logger.info(`🚀 Server listening on port ${port}`); -}; - -export const shutdown = (server) => async () => { - logger.info("🛑 Received SIGTERM, shutting down..."); - if (server && server.close) { - await server.close(); - logger.info("🛑 Server closed"); - } - if (persistenceLayer && persistenceLayer.disconnect) { - await persistenceLayer.disconnect(); - logger.info("🛑 Disconnected from PSQL"); - } - logger.info("🛑 Exiting..."); - return process.exit(0); -}; - -process.on("SIGTERM", shutdown(listeningServer)); - -start(server, handlersPath); +await start(); diff --git a/src/lib/healthcheck.ts b/src/lib/healthcheck.ts deleted file mode 100644 index cd48d24..0000000 --- a/src/lib/healthcheck.ts +++ /dev/null @@ -1,3 +0,0 @@ -export const healthcheck = (request, response) => { - response.status(200).send("ok"); -};