Skip to content

Commit

Permalink
refactor: server listen accept 0 to set random port
Browse files Browse the repository at this point in the history
  • Loading branch information
rsaz committed Dec 3, 2024
1 parent da92bc4 commit 7a97cf1
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 24 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@expressots/adapter-express",
"version": "3.0.0-beta.4",
"version": "3.0.0-beta.4.1",
"description": "Expressots - modern, fast, lightweight nodejs web framework (@adapter-express)",
"author": "",
"main": "./lib/cjs/index.js",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,12 @@ jest.mock("../express-utils/inversify-express-server", () => {
build: jest.fn().mockReturnValue({
set: jest.fn(),
listen: jest.fn().mockImplementation((port, callback) => {
const server = {
on: jest.fn(),
close: jest.fn(),
};
callback();
return { close: jest.fn() };
return server;
}),
}),
})),
Expand Down Expand Up @@ -77,7 +81,7 @@ describe("AppExpress.listen() method", () => {
set: jest.fn(),
listen: jest.fn().mockImplementation((port, callback) => {
callback();
return { close: jest.fn() };
return { on: jest.fn(), close: jest.fn() };
}),
} as unknown as express.Application;

Expand All @@ -97,7 +101,6 @@ describe("AppExpress.listen() method", () => {

expect(mockApp.set).toHaveBeenCalledWith("env", "development");
expect(mockApp.listen).toHaveBeenCalledWith(port, expect.any(Function));
expect(mockConsole.messageServer).toHaveBeenCalledWith(port, "development", undefined);
});

it("should set the environment to development by default", async () => {
Expand All @@ -115,12 +118,6 @@ describe("AppExpress.listen() method", () => {
expect(mockApp.listen).toHaveBeenCalledWith(3000, expect.any(Function));
});

it("should handle invalid port by defaulting to 3000", async () => {
await appExpress.listen(undefined as any);

expect(mockApp.listen).toHaveBeenCalledWith(3000, expect.any(Function));
});

it("should handle process signals for graceful shutdown", async () => {
await appExpress.listen(3000);

Expand Down
36 changes: 25 additions & 11 deletions src/adapter-express/application-express.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { ExpressHandler, MiddlewareConfig } from "./application-express.types";
import { HttpStatusCodeMiddleware } from "./express-utils/http-status-middleware";
import { InversifyExpressServer } from "./express-utils/inversify-express-server";
import { setEngineEjs, setEngineHandlebars, setEnginePug } from "./render/engine";
import { AddressInfo } from "net";

/**
* The AppExpress class provides methods for configuring and running an Express application.
Expand Down Expand Up @@ -240,20 +241,33 @@ export class AppExpress implements Server.IWebServer {
this.environment = this.environment || "development";
this.app.set("env", this.environment);

this.port = typeof port === "string" ? parseInt(port, 10) : port || 3000;
this.serverInstance = this.app.listen(this.port, () => {
this.console.messageServer(this.port, this.environment, appInfo);
this.port = typeof port === "string" ? parseInt(port, 10) : port;

(["SIGTERM", "SIGHUP", "SIGBREAK", "SIGQUIT", "SIGINT"] as Array<NodeJS.Signals>).forEach(
(signal) => {
process.on(signal, this.handleExit.bind(this));
},
);
});
return new Promise<IWebServerPublic>((resolve, reject) => {
this.serverInstance = this.app.listen(this.port, async () => {
this.port = (this.serverInstance?.address() as AddressInfo)?.port;

this.console.messageServer(this.port, this.environment, appInfo);

await this.postServerInitialization();
(["SIGTERM", "SIGHUP", "SIGBREAK", "SIGQUIT", "SIGINT"] as Array<NodeJS.Signals>).forEach(
(signal) => {
process.on(signal, this.handleExit.bind(this));
},
);

return this as IWebServerPublic;
try {
await this.postServerInitialization();
resolve(this as IWebServerPublic);
} catch (error) {
this.logger.error(`Error during post-server initialization: ${error}`, "adapter-express");
reject(error);
}
});
this.serverInstance?.on("error", (error) => {
this.logger.error(`Error starting server: ${error.message}`, "adapter-express");
reject(error);
});
});
}

/**
Expand Down
19 changes: 16 additions & 3 deletions src/adapter-express/micro-api/application-express-micro.ts
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ class AppExpressMicro {
*/
public async listen(port: number | string, appInfo?: IConsoleMessage): Promise<void> {
const logger: Logger = new Logger();
this.port = typeof port === "string" ? parseInt(port, 10) : port || 3000;
const normalizedPort = typeof port === "string" ? parseInt(port, 10) : port;

this.configureMiddleware();

Expand All @@ -246,8 +246,16 @@ class AppExpressMicro {
this.app.use(this.Middleware.getErrorHandler() as express.ErrorRequestHandler);
}

return new Promise((resolve) => {
this.app.listen(this.port, () => {
return new Promise((resolve, reject) => {
const server = this.app.listen(normalizedPort, () => {
const address = server.address();

if (typeof address === "object" && address?.port) {
this.port = address.port;
} else {
this.port = normalizedPort;
}

const appInfoNormalized = appInfo ? `${appInfo?.appName} - ${appInfo?.appVersion} ` : "";
logger.info(`${appInfoNormalized}[${this.port}:${this.environment}]`, "MicroAPI");

Expand All @@ -258,6 +266,11 @@ class AppExpressMicro {
);
resolve();
});

server.on("error", (error) => {
logger.error(`Error starting server: ${error.message}`, "MicroAPI");
reject(error);
});
});
}
}
Expand Down

0 comments on commit 7a97cf1

Please sign in to comment.