mclintprojects / actioncable-vue

A Vue plugin that makes integrating Rails Action Cable dead-easy.
MIT License
182 stars 37 forks source link

Why are the connections duplicated? #31

Closed afuno closed 4 years ago

afuno commented 4 years ago

Rails 6.0.3.2 @rails/actioncable 6.0.3 @types/actioncable 5.2.3 actioncable-vue 2.3.0


I have some list. Each item in this list is wrapped in a component. Inside this component I have a subscription to the channel.

const CHANNEL_NAME = 'GoodNameChannel'

export default {
  props: {
    item: {
      type: Object,
      required: true
    }
  },

  channels: {
    [CHANNEL_NAME]: {
      connected() {
        console.info(
          `${CHANNEL_NAME}: connected()`, this.item.id
        )
      },
      received(data) {
        console.info(
          `${CHANNEL_NAME}: received()`, data
        )
      },
      disconnected() {
        console.info(
          `${CHANNEL_NAME}: disconnected()`
        )
      }
    }
  },

  mounted() {
    this.$cable.subscribe({
      channel: CHANNEL_NAME,
      item_id: this.item.id
    })
  }
}

There are two items in the list. So there are two components within which the subscription takes place.

If we look at the server logs, we will see these two subscriptions:

15:43:20 web.1       | GoodNameChannel is transmitting the subscription confirmation
15:43:20 web.1       | GoodNameChannel is streaming from good_name_item:Z2lkOi8vZ28tc2F5LWFjYWRlbXktc3xhdGZvcm0vTWVzc2VuZ2VyOjpSb29tLzQ0
15:43:20 web.1       | GoodNameChannel is transmitting the subscription confirmation
15:43:20 web.1       | GoodNameChannel is streaming from good_name_item:Z2lkOi8vZ28tc2F5LWFjYWRlbXktc3xhdGZvcm0vTWVzc2VuZ2VyOjpSb29tLzQz

But if look at the result of this code:

console.info(
  `${CHANNEL_NAME}: connected()`
)

Then you can see the following:

GoodNameChannel: connected() 123 GoodNameChannel: connected() 124 GoodNameChannel: connected() 123 GoodNameChannel: connected() 124

That is, this code is executed 4 times.

mounted() is executed twice as expected (once for each component)

Why is this happening?

In other places, where there are more than 2 items (components) in the list, I get not duplication, but item * n, where n is more than 2 or even 4.

mclintprojects commented 4 years ago

@afuno Is this happening only locally? I think the issue is from Vue hot reloads. I'll add a fix that should prevent this duplication.

afuno commented 4 years ago

@mclintprojects No, the server has this problem too. I have a list of 99 items. In the console I see 9801 (99 * 99). But everything is fine on the backend.

I added another item to the list (now there are 100). Now I see 10000 (100 * 100) in the console.

mclintprojects commented 4 years ago

@afuno This issue is definitely because of hot-reloading. Take a look at this. Because of it, each time Vue hot-reloads n subscriptions will be duplicated because the destroy hook is out-of-wack and my clean-up doesn't happen. The fix is to refresh the page.

Also this won't happen in production because there's no hot-reload.

afuno commented 4 years ago

@mclintprojects But this happens in production. My example about 99 items and 100 items is described from production.

But I agree - it looks like a hot update. Any ideas how to fix this?

mclintprojects commented 4 years ago

I tried de-duplicating but the issue is from Vue. Refreshing the page seems to be the only thing that works.

Also by production I mean you build the app and run it. It still happens then?

afuno commented 4 years ago

Refreshing the page does not help, because after refreshing the country, subscriptions occur again.

Yes, of course, building and running the application.

mclintprojects commented 4 years ago

@afuno I just published what I think is a patch for it. Try v2.3.1 and let me know how it goes.

afuno commented 4 years ago

@mclintprojects I have tested version 2.3.2 in production. Nothing has changed on this issue. All the same 10000 logs (100 * 100).

mclintprojects commented 4 years ago

At this point I'll have to take a look at your code. I've fixed the duplication on my end so this is probably from yours.

afuno commented 4 years ago

Can we go to email (which is in your profile) for this?

mclintprojects commented 4 years ago

@afuno Yes, kindly email me.

afuno commented 4 years ago

@mclintprojects I moved the subscription to the channel from each list item component to the root list component. This fixed the problem with "multiplying" subscriptions on the JS side. Thank you.