I'm trying to use NestJS and the NATS microservice. There is good documentation for setting up a basic request-response.
What I did is the following:
Ran a local NATS server.
Set up my main.ts
to connect to the server:
async function bootstrap() {
const app = await NestFactory.createMicroservice(AppModule, {
options: {
url: "nats://localhost:4222",
},
transport: Transport.NATS,
});
app.listen(() => console.log("Microservice is listening"));
}
bootstrap();
Created a ClientProxyFactory to send back messages:
export const NatsClientProvider: Provider = {
inject: [ConfigService],
provide: NatsClientProviderId,
useFactory: async (config: ConfigService) =>
ClientProxyFactory.create({
options: {
servers: config.getNatsConfig().servers,
},
transport: Transport.NATS,
}),
};
Set up a controller app.controller.ts
to respond to a certain pattern:
@Controller()
export class AppController {
constructor(
private readonly appService: AppService,
@Inject(NatsClientProviderId) private readonly natsClient: ClientProxy,
) {}
@MessagePattern("hello")
async getHello(data: string) {
console.log("data: ", data);
console.log("getHello!!");
await this.natsClient.send("hello", this.appService.getHello());
return this.appService.getHello();
}
async onModuleInit() {
await this.natsClient.connect();
console.log("Nats connected!");
}
Set up a test file to try sending a request-response message:
import { connect } from "ts-nats";
async function start() {
const nc = await connect({
servers: ["nats://localhost:4222"],
});
const msg = await nc.request("hello", 5000, "me");
console.log("msg: ", msg);
}
start();
When I run my Nest app, I can see the subscription created properly in the NATS server logs.
When I run the test.ts
file, it times out with NatsError: Request timed out.
. However, I can see my console logs (although the data is undefined
even though I am specifying it in the published message.
Neither the return
nor the client.send
methods are working to receive messages back from the app.
Any help is appreciated!
EDIT: Still looking into and stuck on this issue. In the "Sending Messages" section of the Microservice docs, it says "The pattern has to be equal to this one defined in the @MessagePattern() decorator while payload is a message that we want to transmit to another microservice.". If I do that, the Nest app detects the message it sends and gets stuck in an infinite loop of sending a message and receiving the same message back and forth to itself forever.
To avoid the infinite loop in your controller, remove the natsClient.send
statement. MessagePattern
will automatically send a reply with the data you return from the function, in your case this.appService.getHello()
:
@MessagePattern("hello")
async getHello(data: string) {
console.log("data: ", data);
return "Hello World!";
}
Nest requires you to send a long an id
attribute (any string is fine) for it to be able to reply to a message. Just include it in the data json:
// Nest expects the data to have the following structure
const reply = await nc.request("hello", 500, JSON.stringify({ data: "Hello", id: "myid" }));
console.log({ reply });
In your nest log, you'll see the following log entry:
data: Hello
In your test script, you'll see this:
{ reply:
{ subject: '_INBOX.GJGL6RJFYXKMCF8CWXO0HB.GJGL6RJFYXKMCF8CWXO0B5',
sid: 1,
reply: undefined,
size: 50,
data: '{"err":null,"response":"Hello World!","id":"myid"}'
} }