pusher / pusher-js

Pusher Javascript library
http://pusher.com
MIT License
2.11k stars 374 forks source link

Receiving data multiple times #273

Closed Neha3011 closed 4 years ago

Neha3011 commented 6 years ago

I am facing issue while using authenticated pusher events. When I get any event from pusher, in network tab I see only one event, but when I log inside my code, I get multiple log statements.

My code looks something like this this.privateChannel.bind('eventName', data => { console.log(data) });

My pusher version is 4.2.2. Thank you.

stueynet commented 6 years ago

I can confirm this issue as well. Our code does:

    const channel = pusher.subscribe(`presence-${channelId}`);

    channel.bind('client-eventName', (data) => {
        // do the things
    });

It would seem that channel can get instantiated multiple times during the lifecycle of our app. It does not exist more than one in the pusher.channels object, but it definitely exists multiple times in memory. And when the pusher events come in, the thing fires locally many times (depending on how many times that thing was instantiated).

Is there a better way to check if the subscription already exists?

TomKemp commented 6 years ago

Calling pusher.subscribe a second time with the same channel name will return the same channel object as the first call. It only exists once in memory (see here). You can get a list of all subscribed channels using pusher.allChannels().

However I think your problem is that you are making multiple calls to bind with the same callback. This will result in the same callback being called multiple times when the event occurs. You could make use of unbind before you add new callbacks (see here), or change your application so you're not calling bind multiple times.

stueynet commented 6 years ago

Thanks @TomKemp. Just curious how do you know we are making multiple calls to bind with the same callback? Is that just a common issue?

TomKemp commented 6 years ago

No problem @stueynet. I don't know that for sure, but that's what it sounds like from your description. You said:

channel can get instantiated multiple times during the lifecycle of our app

If channel is getting instantiated multiple times then bind is probably being called multiple times too because they are often called together. And calling bind with the same callback multiple times would lead to your callback firing multiple times when the event is triggered.

stueynet commented 6 years ago

We are finding that it’s not a matter of mutiple bindings but rather duplication of that channel object in memory somehow. So if it exists twice, then the events are handled twice. We tested by adding a random key to that object and over time we see that the pusher event is handled by different versions of channel. It’s super strange.

djcurtis2 commented 6 years ago

Was a solution for this ever found? I'm facing a similar issue in my Angular application where if I navigate away from my component, then back, a new identical event object is generated . I checked the pusher debug console and only one event is being registered so it seems this is happening in memory somehow.

leesio commented 6 years ago

This is very strange. @stueynet / @djcurtis2 are you able to reproduce this in a minimal example so I can try to see what's happening?

djcurtis2 commented 6 years ago

I actually figured out what was happening. Since I was binding to the channel on ngOnInit, when I navigated to another component, then back to the original it was adding another bind to the channel. Unbinding to the channel in my ngOnDestroy event solved the issue for me.

CarlosRamon commented 6 years ago

The problem is that, every time the application is started, a new Pusher client is instantiated. Hence I try to list the channels of the current Pusher client and there really is only one. But in reality there are other Pusher clients from previous instances of the application. As the picture shows. every time I open the app, a new client is started and the previous client reference is lost by the application.

captura de tela de 2018-08-01 10-35-41

I would like to know how to use the same Pusher client, or how to do so once a new Pusher with the same channel_id as the previous one has been created, a finished application can be terminated.

aliraza-dev commented 5 years ago

The problem is that, every time the application is started, a new Pusher client is instantiated. Hence I try to list the channels of the current Pusher client and there really is only one. But in reality there are other Pusher clients from previous instances of the application. As the picture shows. every time I open the app, a new client is started and the previous client reference is lost by the application.

captura de tela de 2018-08-01 10-35-41

I would like to know how to use the same Pusher client, or how to do so once a new Pusher with the same channel_id as the previous one has been created, a finished application can be terminated.

Were you able to solve the mystery?

mark-atkinson-unmind commented 5 years ago

I am encountering a similar issue. Currently if I minimise Chrome, and put the laptop to sleep for a few minutes then I get duplicate responses.

I have made sure that all of our code doesn't re-bind events and re-instantiate pusher, however I can see the Pusher state changing and reconnecting when I re-open Chrome after a few seconds.

At this point I would actually rather disable the auto-subscribe to the channels and just handle it myself but not sure how to go about this?

mdoyle13 commented 4 years ago

I ran into this issue and I solved it by making sure to use channel.unbind when appropriate. It is possible to bind the same callback multiple times.

KarthikUCH commented 4 years ago

Pusher Java lib got the option to bind events along with channel subscription. subscribe(final String channelName, final ChannelEventListener listener, final String... eventNames)

If pusher-js got a similar option, then it should avoid binding an event multiple times.

ponikar commented 4 years ago

I think You have to unsubscribe the currently subscribed channel before subscribing to any other channel. I know it sounds weird!

leesio commented 4 years ago

There's been very little activity on this issue, and I'm not sure how to go about debugging with the information we have now so I'm going to close it.

If you're experiencing this issue and are able to provide more information to help debug it, please feel free to reopen

NathTech commented 4 years ago

This helped me solve this issue on my system. (the Laravel Echo tab of the examples in the below link)

unbinding-from-events

Using laravel-websockets and pusher-php-server on the backend and React, laravel-echo and pusher-js on the front end.

I was getting the above 2 callbacks being fired for one event after joining, leaving and joining the channel again.

My code was running Echo.leave(channelName) to leave a channel but this wasn't unbinding the callbacks. So my code now loops through the callbacks and runs channel.stopListening(eventName) to unbind each of them before leaving the channel

below are my redux thunks for dispatching

export const joinChannel = (channelName, eventHandlers = []) => (dispatch) => {

    const channel = window.Echo.private(channelName)

    eventHandlers.forEach(({ name, handle }) => {
        channel.listen(name, handle)
    })
    dispatch(joinChannelSuccess(channelName))
}

export const leaveChannel = (channelName, eventHandlers = []) => (dispatch) => {

    const channel = window.Echo.private(channelName)

    eventHandlers.forEach(({ name }) => {
        channel.stopListening(name)
    })

    window.Echo.leave(channelName)
    dispatch(leaveChannelSuccess(channelName))
}
kios19 commented 2 years ago

for anyone using this with react native you have to unbind after the callback heres an example

 var channel = pusher.subscribe('test');
        channel.bind('assigned', function(data) {

          if(data.message){
            console.log("some message")
          }
        }, channel.unbind());
skn-036 commented 2 years ago

for laravel echo

const echo = Echo.private(`gmail.token.expired.${user.id}`);

echo.listen('.gmail.token.expired', (event) => {
    // some action
}, echo.stopListening('.gmail.token.expired'))
xsmurphy commented 1 year ago

I was having this same issue, solved by adding unbind before I bind an event, example:

channel.unbind('event').bind('event', (result) => {
//my code here
});
oka-wiadnyana commented 1 year ago

I was having this same issue, solved by adding unbind before I bind an event, example:

channel.unbind('event').bind('event', (result) => {
//my code here
});

Sir...i use your script..but i got error (The listener argument must be type of function. Received undefined)..how to handle this error?

babucarr32 commented 1 year ago

To solve this, you need to unbind the channel before binding.

pusherClient.subscribe(1234); pusherClient.bind(1234); pusherClient.bind("incoming-message", (text) => { console.log(text); });

See here for more info

badalsaibo commented 10 months ago

I had to add a cleanup function on the useEffect

useEffect(() => {
    const subscribeToNotificationsChannel = async () => {
      try {
        pusherInstance.unsubscribe(channelName);

        const channel = pusherInstance.subscribe(channelName);

        channel.bind(PUSHER_CHAT_EVENTS.CHAT_MESSAGE_RECEIVED, (data: any) => {
          console.log('Received notification from chat:', data);
          // queryClient.invalidateQueries({ queryKey: [queryKey] });
          queryClient.setQueryData([queryKey], (prev) => {
            console.log(prev, data);
            return {
              pages: [
                [data, ...prev.pages[0]],
                ...prev.pages.slice(1), // Keep the rest of the pages unchanged
              ],
              pageParams: prev.pageParams,
            };
          });
        });

        // Bind to subscription success event
        channel.bind('pusher:subscription_succeeded', (data: any) => {
          console.log('Subscription succeeded:', data);
        });

        channel.bind('pusher:subscription_error', (err: any) => {
          console.log(err);
        });
      } catch (error) {
        console.error('Error subscribing to notifications channel:', error);
      }
    };

    subscribeToNotificationsChannel();

    return () => {
      pusherInstance.unsubscribe(channelName);
    };
  }, [pusherInstance, channelName, queryClient, queryKey]);