question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

command run doesn't close when functionality contains observable calls via @nestjs/microservices clientProxy.send()

See original GitHub issue

Is there an existing issue for this?

  • I have searched the existing issues

Current behavior

When calling the logic via an HTTP request, it works as expected and request completes.

When calling the logic via a nest-commander command execution, the command hangs after successfully completing all logic.

given the following microservice client:

import { firstValueFrom } from 'rxjs';

import { Injectable } from '@nestjs/common';
import { ClientProxy, ClientProxyFactory } from '@nestjs/microservices';

import { MessagingConfigService } from './messaging.config';

@Injectable()
export class MessagingService {
  private eventsClient: ClientProxy;
  constructor(private readonly configService: MessagingConfigService) {
    this.eventsClient = ClientProxyFactory.create(this.configService.eventsConfig);
  }

  send<R, I = unknown>(pattern: string, data: I) {
    return this.eventsClient.send<R, I>(pattern, data);
  }

  async sendAsync<R, I = unknown>(pattern: string, data: I) {
    return await firstValueFrom(this.send<R, I>(pattern, data));
  }

  emit<R, I = unknown>(pattern: string, data: I) {
    return this.eventsClient.emit<R, I>(pattern, data);
  }

  async emitAsync<R, I = unknown>(pattern: string, data: I) {
    return await firstValueFrom(this.emit<R, I>(pattern, data));
  }
}

calling await this.messagingService.sendAsync('message-pattern', payload) results in the command hanging even though this call returns values. Mind you, running the logic from an HTTP request works as expected, just not from the cli.

Also note that I have tested removing the microservice call and instead hard coded the response value, and it works fine in that instance.

Minimum reproduction code

@Command({
  name: 'test',
  arguments: '<action>',
  description: 'test command'
})
export class TestCommand implements CommandRunner {
  constructor(
    private readonly messagingService: MessagingService
  ) {}

  run(): Promise<void> {
     return this.messagingService.sendAsync('test-subject', {foo: 'bar'})
  }

Expected behavior

Command execution closes on response from sendAsync call.

Package

  • nest-commander
  • nest-commander-schematics
  • nest-commander-testing

Package version

2.3.5

Node.js version

14.18.1

In which operating systems have you tested?

  • macOS
  • Windows
  • Linux

Other

No response

Issue Analytics

  • State:closed
  • Created 2 years ago
  • Comments:5 (3 by maintainers)

github_iconTop GitHub Comments

2reactions
jmcdo29commented, Jan 18, 2022

Seems so, thanks for adding the modification! Glad I could help

1reaction
jmcdo29commented, Jan 18, 2022

Thanks for the reproduction. I was able to reproduce with your code (woohoo), and I have a fix for it. But first, a little background as to what’s happening:

When Nest creates a microservice client (your EventsClient) it’s created lazily. It’s not connected off the bat, and will only connect on manually calling connect as shown in the Nest docs (scroll up just slightly) or when the first event is sent. Because you don’t end up calling sendAsync or send in your MessagingService code unless you use cli examples nats, the client is never connected and you never end up having the hang. But when you do use cli examples nats you connect the client, and it won’t disconnect until told to.

There are two easy solutions here:

  1. Change your send or sendAsync to include a close() call for this.eventsClient. This works okay, but you’ll have to remember it each time, and if you end up making multiple sends you’ll end up opening and closing connections which is slow

  2. Add an OnModuleDestory or OnApplicationShutdown hook and call await this.eventsClient.close(). The top of the service could look like this:

@Injectable()
export class MessagingService implements OnModuleDestroy {
  private eventsClient: ClientProxy;
  private reqClient: AxiosInstance;
  constructor(private readonly configService: MessagingConfigService) {
    this.eventsClient = ClientProxyFactory.create(this.configService.eventsConfig);
    this.reqClient = axios.create();
  }

  async onModuleDestroy() {
    await this.eventsClient.close();
  }

With this, the event was sent, response was logged, and the command exited correctly.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Microservices | NestJS - A progressive Node.js framework
The ClientProxy exposes a send() method. This method is intended to call the microservice and returns an Observable with its response. Thus, we...
Read more >
Testing Microservice client and `Cannot read property 'send' of ...
I'm trying to test microservice and his client controller ... and does not have any other dependency (only get() method to call rpc...
Read more >
Part 5: Completing the Client Component - DEV Community ‍ ‍
We know ClientProxy#send() returns an Observable. The job of that Observable is to consume incoming Faye messages (boxes in the diagram below) ...
Read more >
Nest e2e test : Jest did not exit one second after the test run ...
It might be late but you have to call the close function from the module variable, like this: afterEach(async done => { for...
Read more >
Microservices in NestJS: How to build it? A Guide - SoluteLabs
Looking at the capabilities of an application, a microservice-based architecture has gained popularity in recent years. NestJS is a Node.
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found