Close redis connection when using NestJS Queues
Asked Answered
C

3

6

I'm trying to setup E2E tests in a NestJS project, however, jest output looks like this:

Jest did not exit one second after the test run has completed

After a lot of reading this is because there are some resources, not yet liberated, after some debugging it turns there's an open connection to redis created by ioredis which is used by bull which is used by NestJS to do task queue processing. The thing is that I don't have a reference to the connection in the test code, so how can I close it? I'm tearing down the Nest application in the afterAll jest's hook like this:

  afterAll(async () => {
    await app.close();
  });

but it does nothing, the connection is still there and the jest error message persists. I know I can just add the --forceExit to the jest command but that is not solving anything, it's just hiding the problem under the rug.

Coroner answered 19/7, 2020 at 0:37 Comment(1)
have solved this issue ? i'm suffering from the same problem, after using --detectOpenhandles i realized that ioredis StandaloneConnector has a tcp connection openFrugal
F
3

This took me awhile to figure out. You need to close the module in the afterAll hook. I was able to find this from looking at the tests in the nestJS Bull repo.

describe('RedisTest', () => {
  let module: TestingModule;
  beforeAll(async () => {

    module = Test.createTestingModule({
      imports: [
        BullModule.registerQueueAsync({
          name: 'test2',
        }),
      ],

    });
  });

  afterAll(async () => {
    await module.close();
  });
});

https://github.com/nestjs/bull/blob/master/e2e/module.e2e-spec.ts

Fifteenth answered 17/2, 2021 at 17:4 Comment(0)
F
2

After struggling almost to getting depressed i found a solution that worked for me.
I'm using "@nestjs/bull": "^0.3.1", "bull": "^3.21.1".
because the queue from bull package uses redis, it keeps the connection open although the module & app are closed.

    await moduleRef.close();
    await app.close();

i realized that when using --detectOpenHandles while relying on leaked-handles library for more information, you will see something like this in the console:

    tcp stream {
       fd: 20,
       readable: true,
       writable: false,
       address: {},
       serverAddr: null
    }

    tcp handle leaked at one of: 
    at /media/user/somePartitionName/Workspace/Nest/project- 
    name/node_modules/ioredis/built/connectors/StandaloneConnector.js:58:45
    tcp stream {
       fd: 22,
       readable: true,
       writable: true,
       address: { address: '127.0.0.1', family: 'IPv4', port: 34876 },
       serverAddr: null
    }

Solution using beforEach() & afterEach()

  • in beforEach(), add this instruction to get an instance of your queue :
    queue = moduleRef.get(getQueueToken("queuename"));
  • in afterEach(), close the queue like so: (also close your app & module for better practice)
    await queue.close();

Note

using beforAll() & afterAll() doesn't work and the same problem occurs, at least from what i have tried, both beforEach() & afterEach() work combined.

Frugal answered 27/3, 2021 at 11:21 Comment(1)
The problem now, is that you're allocating and closing a connection for each test, it seems either you leak the connection or have inefficient code (leaking cycles), thank God I'm not touching nodejs again (I know is not nodejs' fault, but still).Coroner
M
2

You don't have to add queue.close() to every test, just close queues in their own service/provider using OnModuleDestroy Hook:

@Injectable()
export class ServicesConsumer implements OnModuleDestroy {
  constructor(
    @InjectQueue('services')
    private readonly servicesQueue: Queue,
  ) { }

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

Mother answered 22/3, 2022 at 14:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.