-
-
Notifications
You must be signed in to change notification settings - Fork 7.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make Microservice creation dependent on the ApplicationContext #2343
Comments
@kamilmysliwiec is this a planned feature? |
I found this solution ->
this is work (usual MICROSERVICES) ! but this appear not work for websockets |
I`m implementing Nest.js powered microservice and I need to do two things. Firstly, I need to get a configuration service in my main.ts file, and pass it as a constructor param to a custom transport strategy. Secondly, I need to do some bootstrapping actions in my service after microservice was bootstrapped. |
The one bit that becomes a sticking point with this example is that lifecycle methods do not work. |
Yes, but you can call the app.init method manually app.startAllMicroservices(async () => {
// Calls the Nest lifecycle events.
await app.init()
logger.log('Microservice is listening...')
}) |
Is this gonna be solved or stay this way with the current workarounds, in my opinion this is pretty trivial usage |
@kamilmysliwiec Is this targeted for some version of Nest? What do you think of the two solutions/workarounds (#1 #2)? Do they have any downsides? E.g. #1 would create everything twice which uses unnecessary ressources and #2 would create a http app with Express unnecessarily running? Personally I would prefer the following method as it does not create a Express server and all lifecycle methods work as expected: async function bootstrap(): Promise<void> {
// TODO: Remove when the following is fixed https://github.com/nestjs/nest/issues/2343
const appContext = await NestFactory.createApplicationContext(AppModule);
const configService = appContext.get(ConfigService);
// TODO End
const app = await NestFactory.createMicroservice<MicroserviceOptions>(AppModule, {
transport: Transport.NATS,
options: {
url: configService.get<string>('nats.url'),
},
});
app.listen(() => {
console.log('Microservice is listening');
});
// TODO: Remove when the following is fixed https://github.com/nestjs/nest/issues/2343
appContext.close();
// TODO End
} |
If your config parser only relies on process.env you could simply instantiate the config parser. server-config.ts
main.ts
|
I use multiple TypeORM DB connections in my application. @Module({
imports: [
TypeOrmModule.forRoot({
// ...
keepConnectionAlive: true,
}),
],
})
export class AppModule {} So with that being said, |
This is how I added this feature to my application by using the env-var package.
import { NestMicroserviceOptions } from '@nestjs/common/interfaces/microservices/nest-microservice-options.interface';
import { MicroserviceOptions, RedisOptions, RmqOptions, TcpOptions, Transport } from '@nestjs/microservices';
import { get } from 'env-var';
export class TransportConfig {
public static getOptions(): NestMicroserviceOptions & MicroserviceOptions {
switch (get('TRANSPORT_LAYER').required().asString()) {
case 'TCP':
return TransportConfig.tcp();
case 'REDIS':
return TransportConfig.redis();
case 'RMQ':
return TransportConfig.rmq();
default:
throw new Error('Unsupported transport layer.');
}
}
private static tcp(): TcpOptions {
return {
transport: Transport.TCP,
options: {
host: get('TCP_HOST').asString(),
port: get('TCP_PORT').asPortNumber(),
},
};
}
private static redis(): RedisOptions {
return {
transport: Transport.REDIS,
options: {
url: get('REDIS_URL').required().asString(),
},
};
}
private static rmq(): RmqOptions {
return {
transport: Transport.RMQ,
options: {
urls: [
{
hostname: get('RMQ_HOST').required().asString(),
port: get('RMQ_PORT').required().asPortNumber(),
username: get('RMQ_USER').required().asString(),
password: get('RMQ_PASS').required().asString(),
},
],
queue: get('RMQ_QUEUE').required().default('...').asString(),
queueOptions: {
durable: false,
},
},
};
}
}
import { NestFactory } from '@nestjs/core';
import { MicroserviceOptions } from '@nestjs/microservices';
import { AppModule } from './app.module';
import { Logger } from '@nestjs/common';
import { TransportConfig } from './transport-config.ts'; // <-- Import it
async function bootstrap() {
const logger = new Logger('Main');
const app = await NestFactory.createMicroservice<MicroserviceOptions>(
AppModule,
TransportConfig.getOptions(), // <-- Use this
);
app.listen(() => logger.log('Microservice is listening'));
}
bootstrap();
# TCP, REDIS, RMQ
TRANSPORT_LAYER=TCP
# TCP
TCP_HOST=localhost
TCP_PORT=3000
# Redis
REDIS_URL=redis://localhost:6379
# RabbitMQ
RMQ_HOST=localhost
RMQ_PORT=5672
RMQ_USER=guest
RMQ_PASS=guest
RMQ_QUEUE=your-lovely-queue |
this seems work fine for me except that I need to close context, before creating a microservice:
@Scrip7 this may be a solution for DB connection problem you mentioned |
Passing in the full import config from "./someConfigFile.ts";
async function bootstrap(): Promise<void> {
// Custom logger
const logger = createLogger("microservice");
// TODO: Remove when the following is fixed https://github.com/nestjs/nest/issues/2343
const appContext = await NestFactory.createApplicationContext(
ConfigModule.forRoot({
load: [config],
}),
{
// Pass in your logger here or just set it to false if you want the
// temporary application context to be silent
logger
}
);
const config = appContext.get(ConfigService);
// TODO End
const port = config.get(`services.thisService.port`);
const app = await NestFactory.createMicroservice<MicroserviceOptions>(
AppModule,
{
transport: Transport.TCP,
options: { port },
},
);
await app.listenAsync();
// TODO: Remove when the following is fixed https://github.com/nestjs/nest/issues/2343
// Close the temporary app context since we no longer need it
appContext.close();
// TODO End
logger.info(`Microservice is listening on port ${port}`);
} |
Any updates on this issue? 👀 |
I too, would like this feature.. and not because I need to load some config beforehand, but I use a lot of custom transport strategies that have injected dependencies. It would be nice not to have to create an express instance and connectMicroservice() or create two app contexts that load the entire dependency tree and establish connections, etc. |
Feature Request
Is your feature request related to a problem? Please describe.
I believe that the way Nestjs is bootstraped could be improved by allowing the definition of the container before the definition of the application.
Take as an example a
ConfigService
that would read all the variables in.env
in order to use them as options to define a new Nestjs Microservice while having the following code, how would you do it?At the moment only 2 solutions come in mind:
ApplicationContext
to be able to get theConfigService
from the container to use it for instantiating the microservice.DependencyInjection
Describe the solution you'd like
I believe that this could be done by instantiating the
ApplicationContext
that loads up theContainer
and then use theApplicationContext
as a parameter for theNestFactory.createMicroservice
method.Teachability, Documentation, Adoption, Migration Strategy
In order to support backwards compatibility you could even allow both the current way in case the paramenter a Module or the following one in case it is an instance of an
ApplicationContext
What is the motivation / use case for changing the behavior?
LoggerService
viaDependecyInjection
and also allow settingconfig
options on it in order to call external services likeLogstash
etc.The text was updated successfully, but these errors were encountered: