Producers or consumers may be closed after the client exits out of scope

Open
#399 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Assessment

Difficulty
4/5
Estimated time
3-5 days
Newbie friendliness
35/100
Issue type
Bug
Clarity
Mostly clear
Activity status
Stale
Tech stack
javascript, node.js

Research direction

No source files or tests are named. Start by running the reproduction against a local Pulsar broker, then trace producer, consumer, and client lifetime handling in the Node.js client; done means a producer or consumer keeps its client usable after the outer function scope ends and a regression test prevents AlreadyClosed during continued sends.

Written by the indexing model from the issue text.

Description

Here is the reproduction code:

const Pulsar = require('pulsar-client');

(async () => {
  // Create a client
  const client = new Pulsar.Client({
    serviceUrl: 'pulsar://localhost:6650'
  });

  // Create a producer
  const producer = await client.createProducer({
    topic: 'persistent://public/default/my-topic',
  });
  
  const sendRecords = async () => {
    // Send a message
    await producer.send({
        data: Buffer.from("hello")
    });

    console.log("sent hello")
    setTimeout(()=>sendRecords(), 1000)
  }

  
  await sendRecords();
})();

The output would be like:

➜  node node index.js
sent hello
sent hello
sent hello
sent hello
sent hello
sent hello
sent hello
node:internal/process/promises:288
            triggerUncaughtException(err, true /* fromPromise */);
            ^

[Error: Failed to send message: AlreadyClosed]

Node.js v18.19.0

After the client exits the outer function's scope, it will eventually be garbage collected. This closes the producers and causes the AlreadyClosed issue.

A workaround is to pass the client ref to the sendRecords function:

  const sendRecords = async (client) => {
    // Send a message
    await producer.send({
        data: Buffer.from("hello")
    });

    console.log("sent hello")
    setTimeout(()=>sendRecords(client), 1000)
  }

  
  await sendRecords(client);

And it works.

A better approach is to keep a reference to the client inside the producer or consumer. This way, as long as we hold a reference to the producer or consumer, the client object will not be garbage collected.

Dominant language
C++
Stars
164
Forks
99
Avg merge
5d 18h
Merged PRs (30d)
2

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

More from apache/pulsar-client-node

All issues in apache/pulsar-client-node

Similar issues

More C++ issues

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.