I use NestJs with modules Microservices and Task Schedule to send data from Client to Service (transport: TCP
). If I use PostMan to test call API, the service receives data, but the run task schedule does not.
1. Project Service runs on port 3000
File main.ts
async function bootstrap() {
const app = await NestFactory.createMicroservice<MicroserviceOptions>(
AppModule,
{
transport: Transport.TCP,
options: {
port: 3000,
},
},
);
await app.listen();
}
bootstrap();
File app.controller.ts
@Controller()
export class AppController {
constructor(private readonly appService: AppService) {}
@MessagePattern({ cmd: 'get_book' })
getBook(bookID: string): BookDTO {
console.log('getBook', bookID);
return this.appService.getBookByID(bookID);
}
}
2. Project Client runs on port 3001 and connect TCP to Project Service on port 3000
File main.ts
async function bootstrap() {
const app = await NestFactory.create(AppModule);
await app.listen(3001);
}
bootstrap();
File app.module.ts
@Module({
imports: [ConfigModule.forRoot(), ScheduleModule.forRoot()],
controllers: [AppController],
providers: [
{
provide: 'BOOKS_SERVICE',
inject: [ConfigService],
useFactory: (configService: ConfigService) => {
return ClientProxyFactory.create({
transport: Transport.TCP,
options: {
host: 'localhost',
port: 3000,
},
});
},
},
],
})
export class AppModule {}
File app.controller.ts
@Controller('booksstore')
export class AppController {
constructor(@Inject('BOOKS_SERVICE') private client: ClientProxy) {}
async onApplicationBootstrap() {
await this.client.connect();
}
@Get(':id')
getBookByID(@Param('id') id) {
return this.client.send({ cmd: 'get_book' }, id); // Service receives data (test call API)
}
@Cron(CronExpression.EVERY_5_SECONDS)
scheduleTest() {
console.log('scheduleTest', new Date());
return this.client.send({ cmd: 'get_book' }, 123); // Service doesn't receive data
}
}
Where is the problem? The function task schedule still runs every 5 seconds, but the Client can not send data to Service (Port 3000).
ClientProxy.send()
returns an Observable. In order for an Observable to start, there must be someone subscribed to it. When a route handler (e.g.@Get(:id)
) returns an Observable, NestJS automatically subscribes to it and sends the first emitted value as a response to the client (Postman).However, a method decorated with
@Cron()
is not a route handler, and if it returns an Observable, NestJS does not automatically subscribe to it, and thus the Observable action is never triggered.The fix is simple - you could invoke
.subscribe()
on the value returned from.send()
:Up to you what you wish to do about possible error handling.