NestJS-Telegraf Telegram bot only handles one request at a time - nestjs

I started building a simple telegram bot using nestjs-telegraf package.
Following the docs, I created the basic AppUpdate service:
#Update()
#Injectable()
export class AppUpdate {
#Command('random')
async onRandom(#Ctx() ctx: Context) {
const resp = await asyncRequestToGetData(ctx.message.text);
await ctx.reply(resp);
}
}
And provided it like this in app.module
#Module({
imports: [
ConfigModule.forRoot({ isGlobal: true }),
TelegrafModule.forRootAsync({
imports: [ConfigModule],
useFactory: (configService: ConfigService) => ({
token: configService.get<string>('TELEGRAM_BOT_TOKEN'),
}),
inject: [ConfigService],
}),
HttpModule,
],
controllers: [AppController],
providers: [AppUpdate, ...],
})
export class AppModule {}
The asyncRequestToGetData is an http call that sometimes takes 10 seconds or more.
And for some reason if another user tries to call the same command on the bot while request is processing, the onRandom is not called until the processing is finished.
Basically, not able to handle concurrent requests.
Was not able to find the reason/solution so far.

Related

How to use a custom middleware with nestjs-telegraf?

I am trying to implement custom Telegraf middleware with nestjs-telegraf library and connection to DB using Prisma.
My AppModule is:
#Module({
imports: [
TelegrafModule.forRootAsync({
imports: [ConfigModule, LoggerModule],
useFactory: (configService: ConfigService, logger: LoggerMiddleware) => {
return {
token: configService.get<string>("TELEGRAM_TOKEN")!,
middlewares: [sessionMiddleware, logger.use]
};
},
inject: [ConfigService, LoggerMiddleware]
}),
PrismaModule
],
controllers: [],
providers: [...someProviders]
})
export class AppModule {}
LoggerMiddleware:
#Injectable()
export class LoggerMiddleware {
constructor(private readonly prisma: PrismaService) {}
async use(ctx: Context, next: NextFunction) {
const listUser = await this.prisma.user.findMany()
console.log('listUser = ', listUser)
next()
}
}
LoggerModule:
#Module({
imports: [PrismaModule],
providers: [LoggerMiddleware, PrismaService],
exports: [LoggerMiddleware]
})
export class LoggerModule {}
It starts without errors and code reaches my logger middleware but then I am getting an error:
TypeError: Cannot read properties of undefined (reading 'prisma')
I have access to Prisma service from another provider and a connection to DB works.
At the start, nest initializes all dependencies successfully but I don't understand why during execution it fell with this error. What did I do wrong?
The answer was given by Alexander Bukhalo on github

nest.js HttpModule.registerAsync() ,how to get the original request headers /cookies?

In nest.js, Iam trying to forward cookies/headers from my orirginal request to next api in the call chain. api1->api2->api3 . any headers/cookies from api1 should be automatically included in other https service calls.
HttpModule.registerAsync({
imports: [ConfigModule],
useFactory: async (configService: ConfigService) => ({
timeout: configService.get('HTTP_TIMEOUT'),
maxRedirects: configService.get('HTTP_MAX_REDIRECTS'),
}),
inject: [ConfigService],
});

NestJs with Fastify doesn't execute code after app.listen()

this is my first question here, so i'd like to apologize in advance if i miss something important.
So this is pretty basic, but i didn't find an answer anywhere, as the title states, my NestJs application running with Fastify, simply does not execute any code after the app.listen('port') line, this doesn't happen with Express. OBS: I'm referring to the main.ts file.
relevant code below:
async function bootstrap() {
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter({ logger: { level: 'warn' } }),
);
const configService = app.get(ConfigService);
await app.listen(configService.get<number>(ENV_KEYS.PORT), '0.0.0.0');
console.log(
`Application is running on: ${await app.getUrl()}\nApplication Version: ${version}`,
);
}
bootstrap();
The console.log() after await app.listen never executes, even if the app is working normally, and as far as my tests show, no code after await app.listen() ever executes.
I'd like to know how to overcome this issue, because i need to run some code after the app is already bootstrapped.
So thanks to #Micael Levi pointing me to an issue on github (github.com/nestjs/nest/issues/7572) i started to look into problems within my controllers, and the reason to freeze the application on app.listen() was because of "an double instance" of my AuthController, let me explain
I had my AuthController defined on AuthModule:
// auth.module.ts
#Module({
imports: [
PassportModule,
JwtModule.register({
secret: JWT_CONSTANTS.SECRET,
}),
],
controllers: [AuthController],
providers: [AuthService, LocalStrategy, JwtStrategy],
exports: [AuthService, LocalStrategy, JwtStrategy],
})
And in the AppModule, i was importing AuthModule while also declaring AuthController AGAIN:
// app.module.ts
#Module({
imports: [
ConfigModule.forRoot(getConfigServiceConfiguration()),
TypeOrmModule.forRootAsync({
useFactory: async (configService: ConfigService) =>
getDatabaseModuleOptionsAsync(configService),
inject: [ConfigService],
}),
AuthModule, // <-AuthController is declared within AuthModule scope
UsuarioModule,
ClienteModule,
],
controllers: [AppController, AuthController] // <- AuthController here again,
providers: [AppService],
})
Removing AuthController from controllers:[] in AppModule solved my problem. Rookie mistake, but for some reason this isn't a problem with express, and doesn't raise any compilation errors with Fastify either!

Dotenv variable is undefined

I have one module (auth module) where I register JwtModule:
JwtModule.register({
secret: process.env.SECRET_KEY,
signOptions: { expiresIn: '60m' },
}),
Register function looks like this: static register(options: JwtModuleOptions): DynamicModule;
JwtModule is defined in node_modules (jwt.module.js)
let JwtModule = JwtModule_1 = class JwtModule {
static register(options) {
console.log(options);
console.log(process.env.SECRET_KEY);
return {
module: JwtModule_1,
providers: jwt_providers_1.createJwtProvider(options)
};
}
In app.module.ts I have
ConfigModule.forRoot({
isGlobal: true,
}),
process.env.SECRET_KEY is undefined in node_modules file (console.log(process.env.SECRET_KEY)), but signOptions: { expiresIn: '60m' } is defined.
If I try to write to console SECRET_KEY from .env everywhere else is defined, but in node_modules is undefined.
The ConfigModule's ConfigService runs dotenv's config() method, but all decorators run at the same time, so the config() method is not called yet. You can use the async registration instead and use the ConfigService like so
JwtModule.registerAsync({
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
secret: config.get('SECRET_KEY')
})
})
Be sure that you Call the ConfigService in your App Module constructor :
export class AppModule {
constructor(private configService: ConfigService) {}
}

NestJS, using typeorm on providers

I want to make a provider which queries an entity from db. (what interests me actually is to make typeorm available when I create a provider).
I get
[ExceptionHandler] Connection "default" was not found. - {"trace":"ConnectionNotFoundError: Connection \"default\" was not found.\n
I tried using service, using custom repository, nothing works. I have something like this in module:
{
provide: MICROSERVICE_ID,
useFactory: async (): Promise<Microservice> => {
//ignore logic
return await getRepository(Microservice).findOne(1);
},
inject: []
}
TypeOrm is imported on app.module.ts
TypeOrmModule.forRootAsync({
imports: [ConfigModule],
inject: [ConfigService],
useFactory: async (configService: ConfigService) => (configService.get('database'))
}),
Any help is appreciated.
Check your database file. The Entity may not load as expected.
For newest NestJS version. We should load from ./dist/
Fixed by injecting Connection from typeorm.
import { getRepository, Connection } from 'typeorm';
{
provide: MICROSERVICE_ID,
useFactory: async (): Promise<Microservice> => {
//ignore logic
return await getRepository(Microservice).findOne(1);
},
inject: [Connection]
}

Resources