You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Thanks for the quick reply! I am using subscribe, but as far I can see from the example you have to manually call receive on the subscriber in a loop to get messages?
@mhaagens You are correct. The subscribe command is used to register your consumer on the Pulsar broker, so it will know that you want to receive the messages. After you had subscribed, you have to make a call as shown on line 39 of the example code; const msg = await consumer.receive(); to get the message. It is a blocking call that will deliver one message (if and when it is available).
Okay, so am I understanding it correctly that there’s no way to set up a listener that processes messages as they come in? Similar to this in kafka-Node;
consumer.on('message', function (message) { console.log(message); });
I tried the listener implementation with the following code, that listens forever to messages and once any key received we close the consumer and client (in real-life: instead of listening to any key, we will listen to shutdown signals) -
constPulsar=require('pulsar-client');constreadline=require('readline');constrl=newreadline.createInterface({input: process.stdin,output: process.stdout})functionprompt(){returnnewPromise((resolve)=>{rl.question(`press any key to stop consuming`,()=>resolve());})}(async()=>{// Create a clientconstclient=newPulsar.Client({serviceUrl: 'pulsar://localhost:6650'//operationTimeoutSeconds: 30,});// Create a consumerconstconsumer=awaitclient.subscribe({topic: 'persistent://public/default/my-topic',subscription: 'sub1',subscriptionType: 'Shared',ackTimeoutMs: 10000,listener: function(msg,consumer){console.log(msg.getData().toString());consumer.acknowledge(msg);}});awaitprompt();awaitconsumer.close();awaitclient.close();})();
I have producer which emits at regular intervals (after some time, fails on this - #78 and I restart it).
The consumer after some random time, just closes the connection. I added std::cout to the code and I see Consumer deconstructor is called for every message (which makes sense, since we create for every message a consumer) and the Client deconstructor is called after a while.
I did some changes in order to solve this and it works now, except the listener don't get the consumer instance.
Before the PR, the second call to Close would fail with an Already Closed error, but without crashing Node.
I wrote the original listener implementation, thanks for cleaning it up! Most of the reason it was messy was that I couldn't find a better way to not crash and not leak any memory. It's really annoying due to how the pulsar C interface was made.
The problem is that the C interface creates a pulsar_consumer_t on the stack and passes it to the message listener (here). The consumer it receives is a shared pointer, but the one that is passed to the message listener can't be used after the original message listener function has returned due to this. I think the golang client wrapper workaround for this leaks memory, but I'm not sure. It saves a pointer to the consumer and channel to be used by the listener but I can't find where it deletes the pointer.
Maybe we could add a function to the C interface that clones a pulsar_consumer_t, creating a new shared pointer to the same C++ consumer, and that has to be freed manually? This would allow libraries like this to clone the consumer received by the message listener callback to use it later to ack the message. That would simplify wrapper libraries a lot.
Activity
david-streamlio commentedon Dec 16, 2019
@mhaagens In order to receive messages, you will want to use the
subscribemethod as shown in the following example: https://github.com/apache/pulsar-client-node/blob/master/examples/consumer.jsmhaagens commentedon Dec 16, 2019
Thanks for the quick reply! I am using subscribe, but as far I can see from the example you have to manually call receive on the subscriber in a loop to get messages?
david-streamlio commentedon Dec 16, 2019
@mhaagens You are correct. The
subscribecommand is used to register your consumer on the Pulsar broker, so it will know that you want to receive the messages. After you had subscribed, you have to make a call as shown on line 39 of the example code;const msg = await consumer.receive();to get the message. It is a blocking call that will deliver one message (if and when it is available).HTH
mhaagens commentedon Dec 16, 2019
Okay, so am I understanding it correctly that there’s no way to set up a listener that processes messages as they come in? Similar to this in kafka-Node;
consumer.on('message', function (message) { console.log(message); });david-streamlio commentedon Dec 16, 2019
@mhaagens Not yet, but there appears to be a PR in process now to add this capability. #56
mhaagens commentedon Dec 16, 2019
Awesome, thanks!
mhaagens commentedon Dec 17, 2019
Would this be a solution in the meantime?
david-streamlio commentedon Dec 17, 2019
@mhaagens Yes.
yosiat commentedon Mar 18, 2020
Hi!
I tried the listener implementation with the following code, that listens forever to messages and once any key received we close the consumer and client (in real-life: instead of listening to any key, we will listen to shutdown signals) -
I have producer which emits at regular intervals (after some time, fails on this - #78 and I restart it).
The consumer after some random time, just closes the connection. I added
std::coutto the code and I seeConsumerdeconstructor is called for every message (which makes sense, since we create for every message a consumer) and theClientdeconstructor is called after a while.I did some changes in order to solve this and it works now, except the
listenerdon't get theconsumerinstance.Changes are here - master...yosiat:consumer-listener-bug
If my changes make sense to you, I am happy to open a PR and move the discussion over there.
sijie commentedon Mar 18, 2020
@yosiat yes. this approach looks good to me. Can you create a pull request for your proposed change?
yosiat commentedon Mar 19, 2020
@sijie created a PR, here: #83
gperinazzo commentedon Apr 13, 2020
@yosiat I'm seeing a crash if a client with listener is closed twice after your pull request:
Crashes with the following output:
Before the PR, the second call to Close would fail with an Already Closed error, but without crashing Node.
I wrote the original listener implementation, thanks for cleaning it up! Most of the reason it was messy was that I couldn't find a better way to not crash and not leak any memory. It's really annoying due to how the pulsar C interface was made.
The problem is that the C interface creates a
pulsar_consumer_ton the stack and passes it to the message listener (here). The consumer it receives is a shared pointer, but the one that is passed to the message listener can't be used after the original message listener function has returned due to this. I think the golang client wrapper workaround for this leaks memory, but I'm not sure. It saves a pointer to the consumer and channel to be used by the listener but I can't find where it deletes the pointer.Maybe we could add a function to the C interface that clones a
pulsar_consumer_t, creating a new shared pointer to the same C++ consumer, and that has to be freed manually? This would allow libraries like this to clone the consumer received by the message listener callback to use it later to ack the message. That would simplify wrapper libraries a lot.alphara commentedon Jul 2, 2020
The listener works for consumer. But it does not work for reader:
Do you want to implement it?
yosiat commentedon Jul 2, 2020
@alphara looks like the c/c++ which we rely upon don't support listener for reader interface.
gperinazzo commentedon Jul 2, 2020
I think it is supported on version 2.4.0. Here's the relevant function.
hrsakai commentedon Dec 15, 2021
listener has already been supported, so I closed this issue.