mirror of
https://github.com/nestjs/nest.git
synced 2026-02-21 23:11:44 +00:00
feat(core): change listen to reject on server bind failures
pr update
This commit is contained in:
47
integration/nest-application/listen/e2e/express.spec.ts
Normal file
47
integration/nest-application/listen/e2e/express.spec.ts
Normal file
@@ -0,0 +1,47 @@
|
|||||||
|
import { ExpressAdapter } from '@nestjs/platform-express';
|
||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { expect } from 'chai';
|
||||||
|
import * as express from 'express';
|
||||||
|
import { AppModule } from '../src/app.module';
|
||||||
|
import { INestApplication } from '@nestjs/common';
|
||||||
|
|
||||||
|
describe('Listen (Express Application)', () => {
|
||||||
|
let testModule: TestingModule;
|
||||||
|
let app: INestApplication;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
testModule = await Test.createTestingModule({
|
||||||
|
imports: [AppModule],
|
||||||
|
}).compile();
|
||||||
|
app = testModule.createNestApplication(new ExpressAdapter(express()));
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
app.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should resolve with httpServer on success', async () => {
|
||||||
|
const response = await app.listen(3000);
|
||||||
|
expect(response).to.eql(app.getHttpServer());
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reject if the port is not available', async () => {
|
||||||
|
await app.listen(3000);
|
||||||
|
const secondApp = testModule.createNestApplication(
|
||||||
|
new ExpressAdapter(express()),
|
||||||
|
);
|
||||||
|
try {
|
||||||
|
await secondApp.listen(3000);
|
||||||
|
} catch (error) {
|
||||||
|
expect(error.code).to.equal('EADDRINUSE');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reject if there is an invalid host', async () => {
|
||||||
|
try {
|
||||||
|
await app.listen(3000, '1');
|
||||||
|
} catch (error) {
|
||||||
|
expect(error.code).to.equal('EADDRNOTAVAIL');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
46
integration/nest-application/listen/e2e/fastify.spec.ts
Normal file
46
integration/nest-application/listen/e2e/fastify.spec.ts
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
import { FastifyAdapter } from '@nestjs/platform-fastify';
|
||||||
|
import { Test, TestingModule } from '@nestjs/testing';
|
||||||
|
import { expect } from 'chai';
|
||||||
|
import { AppModule } from '../src/app.module';
|
||||||
|
import { INestApplication } from '@nestjs/common';
|
||||||
|
|
||||||
|
describe('Listen (Fastify Application)', () => {
|
||||||
|
let testModule: TestingModule;
|
||||||
|
let app: INestApplication;
|
||||||
|
|
||||||
|
beforeEach(async () => {
|
||||||
|
testModule = await Test.createTestingModule({
|
||||||
|
imports: [AppModule],
|
||||||
|
}).compile();
|
||||||
|
app = testModule.createNestApplication(new FastifyAdapter());
|
||||||
|
});
|
||||||
|
|
||||||
|
afterEach(async () => {
|
||||||
|
app.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should resolve with httpServer on success', async () => {
|
||||||
|
const response = await app.listen(3000);
|
||||||
|
expect(response).to.eql(app.getHttpServer());
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reject if the port is not available', async () => {
|
||||||
|
await app.listen(3000);
|
||||||
|
const secondApp = testModule.createNestApplication(new FastifyAdapter());
|
||||||
|
try {
|
||||||
|
await secondApp.listen(3000);
|
||||||
|
} catch (error) {
|
||||||
|
expect(error.code).to.equal('EADDRINUSE');
|
||||||
|
}
|
||||||
|
|
||||||
|
await secondApp.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reject if there is an invalid host', async () => {
|
||||||
|
try {
|
||||||
|
await app.listen(3000, '1');
|
||||||
|
} catch (error) {
|
||||||
|
expect(error.code).to.equal('EADDRNOTAVAIL');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
12
integration/nest-application/listen/src/app.controller.ts
Normal file
12
integration/nest-application/listen/src/app.controller.ts
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
import { Controller, Get } from '@nestjs/common';
|
||||||
|
import { AppService } from './app.service';
|
||||||
|
|
||||||
|
@Controller()
|
||||||
|
export class AppController {
|
||||||
|
constructor(private readonly appService: AppService) {}
|
||||||
|
|
||||||
|
@Get()
|
||||||
|
getHello(): string {
|
||||||
|
return this.appService.sayHello();
|
||||||
|
}
|
||||||
|
}
|
||||||
9
integration/nest-application/listen/src/app.module.ts
Normal file
9
integration/nest-application/listen/src/app.module.ts
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
import { Module } from '@nestjs/common';
|
||||||
|
import { AppController } from './app.controller';
|
||||||
|
import { AppService } from './app.service';
|
||||||
|
|
||||||
|
@Module({
|
||||||
|
controllers: [AppController],
|
||||||
|
providers: [AppService],
|
||||||
|
})
|
||||||
|
export class AppModule {}
|
||||||
8
integration/nest-application/listen/src/app.service.ts
Normal file
8
integration/nest-application/listen/src/app.service.ts
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AppService {
|
||||||
|
sayHello(): string {
|
||||||
|
return 'Hello World!';
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -12,7 +12,7 @@ describe('ErrorGateway', () => {
|
|||||||
providers: [ErrorGateway],
|
providers: [ErrorGateway],
|
||||||
}).compile();
|
}).compile();
|
||||||
app = await testingModule.createNestApplication();
|
app = await testingModule.createNestApplication();
|
||||||
await app.listenAsync(3000);
|
await app.listen(3000);
|
||||||
});
|
});
|
||||||
|
|
||||||
it(`should handle error`, async () => {
|
it(`should handle error`, async () => {
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ describe('WebSocketGateway (ack)', () => {
|
|||||||
|
|
||||||
it(`should handle message with ack (http)`, async () => {
|
it(`should handle message with ack (http)`, async () => {
|
||||||
app = await createNestApp(AckGateway);
|
app = await createNestApp(AckGateway);
|
||||||
await app.listenAsync(3000);
|
await app.listen(3000);
|
||||||
|
|
||||||
ws = io.connect('http://localhost:8080');
|
ws = io.connect('http://localhost:8080');
|
||||||
await new Promise<void>(resolve =>
|
await new Promise<void>(resolve =>
|
||||||
@@ -30,7 +30,7 @@ describe('WebSocketGateway (ack)', () => {
|
|||||||
|
|
||||||
it(`should handle message with ack & without data (http)`, async () => {
|
it(`should handle message with ack & without data (http)`, async () => {
|
||||||
app = await createNestApp(AckGateway);
|
app = await createNestApp(AckGateway);
|
||||||
await app.listenAsync(3000);
|
await app.listen(3000);
|
||||||
|
|
||||||
ws = io.connect('http://localhost:8080');
|
ws = io.connect('http://localhost:8080');
|
||||||
await new Promise<void>(resolve =>
|
await new Promise<void>(resolve =>
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ describe('WebSocketGateway', () => {
|
|||||||
|
|
||||||
it(`should handle message (2nd port)`, async () => {
|
it(`should handle message (2nd port)`, async () => {
|
||||||
app = await createNestApp(ApplicationGateway);
|
app = await createNestApp(ApplicationGateway);
|
||||||
await app.listenAsync(3000);
|
await app.listen(3000);
|
||||||
|
|
||||||
ws = io.connect('http://localhost:8080');
|
ws = io.connect('http://localhost:8080');
|
||||||
ws.emit('push', {
|
ws.emit('push', {
|
||||||
@@ -35,7 +35,7 @@ describe('WebSocketGateway', () => {
|
|||||||
|
|
||||||
it(`should handle message (http)`, async () => {
|
it(`should handle message (http)`, async () => {
|
||||||
app = await createNestApp(ServerGateway);
|
app = await createNestApp(ServerGateway);
|
||||||
await app.listenAsync(3000);
|
await app.listen(3000);
|
||||||
|
|
||||||
ws = io.connect('http://localhost:3000');
|
ws = io.connect('http://localhost:3000');
|
||||||
ws.emit('push', {
|
ws.emit('push', {
|
||||||
@@ -51,7 +51,7 @@ describe('WebSocketGateway', () => {
|
|||||||
|
|
||||||
it(`should handle message (2 gateways)`, async () => {
|
it(`should handle message (2 gateways)`, async () => {
|
||||||
app = await createNestApp(ApplicationGateway, NamespaceGateway);
|
app = await createNestApp(ApplicationGateway, NamespaceGateway);
|
||||||
await app.listenAsync(3000);
|
await app.listen(3000);
|
||||||
|
|
||||||
ws = io.connect('http://localhost:8080');
|
ws = io.connect('http://localhost:8080');
|
||||||
io.connect('http://localhost:8080/test').emit('push', {});
|
io.connect('http://localhost:8080/test').emit('push', {});
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ describe('WebSocketGateway (WsAdapter)', () => {
|
|||||||
|
|
||||||
it(`should handle message (2nd port)`, async () => {
|
it(`should handle message (2nd port)`, async () => {
|
||||||
app = await createNestApp(ApplicationGateway);
|
app = await createNestApp(ApplicationGateway);
|
||||||
await app.listenAsync(3000);
|
await app.listen(3000);
|
||||||
|
|
||||||
ws = new WebSocket('ws://localhost:8080');
|
ws = new WebSocket('ws://localhost:8080');
|
||||||
await new Promise(resolve => ws.on('open', resolve));
|
await new Promise(resolve => ws.on('open', resolve));
|
||||||
@@ -44,7 +44,7 @@ describe('WebSocketGateway (WsAdapter)', () => {
|
|||||||
|
|
||||||
it(`should handle message (http)`, async () => {
|
it(`should handle message (http)`, async () => {
|
||||||
app = await createNestApp(ServerGateway);
|
app = await createNestApp(ServerGateway);
|
||||||
await app.listenAsync(3000);
|
await app.listen(3000);
|
||||||
|
|
||||||
ws = new WebSocket('ws://localhost:3000');
|
ws = new WebSocket('ws://localhost:3000');
|
||||||
await new Promise(resolve => ws.on('open', resolve));
|
await new Promise(resolve => ws.on('open', resolve));
|
||||||
@@ -69,7 +69,7 @@ describe('WebSocketGateway (WsAdapter)', () => {
|
|||||||
this.retries(10);
|
this.retries(10);
|
||||||
|
|
||||||
app = await createNestApp(ApplicationGateway, CoreGateway);
|
app = await createNestApp(ApplicationGateway, CoreGateway);
|
||||||
await app.listenAsync(3000);
|
await app.listen(3000);
|
||||||
|
|
||||||
// open websockets delay
|
// open websockets delay
|
||||||
await new Promise(resolve => setTimeout(resolve, 1000));
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
||||||
|
|||||||
34237
package-lock.json
generated
34237
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -54,15 +54,6 @@ export interface INestApplication extends INestApplicationContext {
|
|||||||
*/
|
*/
|
||||||
getUrl(): Promise<string>;
|
getUrl(): Promise<string>;
|
||||||
|
|
||||||
/**
|
|
||||||
* Starts the application (can be awaited).
|
|
||||||
*
|
|
||||||
* @param {number|string} port
|
|
||||||
* @param {string} [hostname]
|
|
||||||
* @returns {Promise}
|
|
||||||
*/
|
|
||||||
listenAsync(port: number | string, hostname?: string): Promise<any>;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Registers a prefix for every HTTP route path.
|
* Registers a prefix for every HTTP route path.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -228,25 +228,26 @@ export class NestApplication
|
|||||||
this.httpAdapter.enableCors(options);
|
this.httpAdapter.enableCors(options);
|
||||||
}
|
}
|
||||||
|
|
||||||
public async listen(
|
public async listen(port: number | string): Promise<any>;
|
||||||
port: number | string,
|
public async listen(port: number | string, hostname: string): Promise<any>;
|
||||||
callback?: () => void,
|
|
||||||
): Promise<any>;
|
|
||||||
public async listen(
|
|
||||||
port: number | string,
|
|
||||||
hostname: string,
|
|
||||||
callback?: () => void,
|
|
||||||
): Promise<any>;
|
|
||||||
public async listen(port: number | string, ...args: any[]): Promise<any> {
|
public async listen(port: number | string, ...args: any[]): Promise<any> {
|
||||||
!this.isInitialized && (await this.init());
|
!this.isInitialized && (await this.init());
|
||||||
this.isListening = true;
|
|
||||||
this.httpAdapter.listen(port, ...args);
|
|
||||||
return this.httpServer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public listenAsync(port: number | string, hostname?: string): Promise<any> {
|
return new Promise((resolve, reject) => {
|
||||||
return new Promise(resolve => {
|
const errorHandler = e => {
|
||||||
const server: any = this.listen(port, hostname, () => resolve(server));
|
this.logger.error(e.toString());
|
||||||
|
reject(e);
|
||||||
|
};
|
||||||
|
this.httpServer.once('error', errorHandler);
|
||||||
|
|
||||||
|
this.httpAdapter.listen(port, ...args, () => {
|
||||||
|
const address = this.httpServer.address();
|
||||||
|
if (address) {
|
||||||
|
this.httpServer.removeListener('error', errorHandler);
|
||||||
|
this.isListening = true;
|
||||||
|
resolve(this.httpServer);
|
||||||
|
}
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -256,30 +257,33 @@ export class NestApplication
|
|||||||
this.logger.error(MESSAGES.CALL_LISTEN_FIRST);
|
this.logger.error(MESSAGES.CALL_LISTEN_FIRST);
|
||||||
reject(MESSAGES.CALL_LISTEN_FIRST);
|
reject(MESSAGES.CALL_LISTEN_FIRST);
|
||||||
}
|
}
|
||||||
this.httpServer.on('listening', () => {
|
const address = this.httpServer.address();
|
||||||
const address = this.httpServer.address();
|
resolve(this.formatAddress(address));
|
||||||
if (typeof address === 'string') {
|
|
||||||
if (platform() === 'win32') {
|
|
||||||
return address;
|
|
||||||
}
|
|
||||||
const basePath = encodeURIComponent(address);
|
|
||||||
return `${this.getProtocol()}+unix://${basePath}`;
|
|
||||||
}
|
|
||||||
let host = this.host();
|
|
||||||
if (address && address.family === 'IPv6') {
|
|
||||||
if (host === '::') {
|
|
||||||
host = '[::1]';
|
|
||||||
} else {
|
|
||||||
host = `[${host}]`;
|
|
||||||
}
|
|
||||||
} else if (host === '0.0.0.0') {
|
|
||||||
host = '127.0.0.1';
|
|
||||||
}
|
|
||||||
resolve(`${this.getProtocol()}://${host}:${address.port}`);
|
|
||||||
});
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private formatAddress(address) {
|
||||||
|
if (typeof address === 'string') {
|
||||||
|
if (platform() === 'win32') {
|
||||||
|
return address;
|
||||||
|
}
|
||||||
|
const basePath = encodeURIComponent(address);
|
||||||
|
return `${this.getProtocol()}+unix://${basePath}`;
|
||||||
|
}
|
||||||
|
let host = this.host();
|
||||||
|
if (address && address.family === 'IPv6') {
|
||||||
|
if (host === '::') {
|
||||||
|
host = '[::1]';
|
||||||
|
} else {
|
||||||
|
host = `[${host}]`;
|
||||||
|
}
|
||||||
|
} else if (host === '0.0.0.0') {
|
||||||
|
host = '127.0.0.1';
|
||||||
|
}
|
||||||
|
|
||||||
|
return `${this.getProtocol()}://${host}:${address.port}`;
|
||||||
|
}
|
||||||
|
|
||||||
public setGlobalPrefix(prefix: string): this {
|
public setGlobalPrefix(prefix: string): this {
|
||||||
this.config.setGlobalPrefix(prefix);
|
this.config.setGlobalPrefix(prefix);
|
||||||
return this;
|
return this;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ async function bootstrap() {
|
|||||||
* transport: Transport.TCP,
|
* transport: Transport.TCP,
|
||||||
* options: { retryAttempts: 5, retryDelay: 3000 },
|
* options: { retryAttempts: 5, retryDelay: 3000 },
|
||||||
* });
|
* });
|
||||||
* await app.listenAsync();
|
* await app.listen();
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
const app = await NestFactory.create(AppModule);
|
const app = await NestFactory.create(AppModule);
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ async function bootstrap() {
|
|||||||
* protoPath: join(__dirname, './hero/hero.proto'),
|
* protoPath: join(__dirname, './hero/hero.proto'),
|
||||||
* }
|
* }
|
||||||
* });
|
* });
|
||||||
* await app.listenAsync();
|
* await app.listen();
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
const app = await NestFactory.create(AppModule);
|
const app = await NestFactory.create(AppModule);
|
||||||
|
|||||||
Reference in New Issue
Block a user