probil/vue-socket.io-extended

Events are not properly executed

pistol-whip opened this issue · 7 comments

Events are only executed one minute after they have been received and then are executed repeatedly every minute.

Could you please provide some code? It's really hard to understand what's wrong without it.

import Vue          from 'vue';
import App          from '@/App.vue';
import VueRouter    from 'vue-router';

import i18n         from '@/i18n';
import vco          from "v-click-outside";
import Vuelidate    from 'vuelidate';
import BootstrapVue from 'bootstrap-vue';
import VueSocketIOExt from 'vue-socket.io-extended';
import io             from 'socket.io-client/dist/socket.io';
import VueSweetalert2 from 'vue-sweetalert2';
import VueApexCharts  from 'vue-apexcharts';
import VueMask        from 'v-mask';
import Scrollspy      from 'vue2-scrollspy';
import vueCountryRegionSelect from 'vue-country-region-select';

import store        from '@/state/store';
import router       from '@/router/index';

import "@/design/index.scss";

const socket = io(process.env.VUE_APP_WS_HOST, {
  path: '/connect',
  transports: ['websocket']
});
Vue.use(VueSocketIOExt, socket);

Vue.config.productionTip = false;

Vue.use(VueRouter);
Vue.use(BootstrapVue);
Vue.use(Vuelidate);
Vue.use(vco);
Vue.use(VueSweetalert2);
Vue.use(VueMask);
Vue.use(require('vue-chartist'));
Vue.component('apexchart', VueApexCharts);
Vue.use(vueCountryRegionSelect);

let ws_times = [];
let ws_time;

fetch(process.env.VUE_APP_ROOT_API + 'v1/status', {credentials: 'include'})
.then(response => {
  if(response.ok){
    return response.json();
  } else{
    console.log(`[CRITICAL] Failed to connect core API: (${response.status})${response.statusText}`);
  }
})
.then(data => {
  fetch(process.env.VUE_APP_ROOT_API + 'v1/setup', {credentials: 'include'})
    .then(response => {
      if(response.ok){
        return response.json();
      } else{
        console.log(`[CRITICAL] Failed to connect core API: (${response.status})${response.statusText}`);
        if(response.status == 401) {
          // NOT LOGGED IN
          location.replace(process.env.VUE_APP_AUTH_PROVIDER);
        }
      }
    })
    .then(data => {
      /* Initialize main Vue instance */
      new Vue({
        router,
        store,
        i18n,
        fallbackLocale: 'en',
        render: h => h(App),
        sockets: {
          connect: function() {
            console.log('CONNECT');
            setInterval(function () {
              ws_time = (new Date).getTime();
              socket.emit('keepalive');
            }, 5000);
          },
          keepalive() {
            console.log(`KEEPALIVE`);
            socket.emit('refresh');
          }
        }
      }).$mount('#app')
    }).catch(error => {
    console.log(`[ERROR] "${error}"`);
    Vue.swal({
      icon: 'error',
      text: 'Sorry, we have encountered an issue serving this request (E:1)'
    }).then(function(){
      location.reload();
    });
  });
})
.catch(error => {
  console.log(`[ERROR] "${error}"`);
  Vue.swal({
    icon: 'error',
    text: 'Sorry, we have encountered an issue serving this request (E:0)'
  }).then(function(){
    location.reload();
  });
});

This is my main.js. Basically what happens is that I can compile the app. Open it in either dev or deployed. It connects to the web socket server and receives events but does not internally process them (or rather, with a minute delay). I have debugged a bit further and could see the messages in the internal buffer, so I am at an absolute loss what is happening.

/edit: Sending also works

@pistol-whip Since your app is initialized asynchronously your listeners on the root component are not able to catch events fired in between initial script execution and component being mounted. There are a lot of caveats with components because they are not available all the time. Components are not designed for that, they were made for rendering.

Socket support on components is limited only due life time of the component.

Your case seems advance so I suggest you either

  1. listen to messages directly on socket instance (the same code as about but rewritten):
socket.on('connect', () => {
  console.log('CONNECT');
  setInterval(function () {
    ws_time = (new Date).getTime();
    socket.emit('keepalive');
  }, 5000);
})
socket.on('keepalive', () => {
  console.log(`KEEPALIVE`);
  socket.emit('refresh');
})

In this case you would remove vue-socket.io-extended out of the equation

  1. Use Vuex store integration. Vuex was designed for data manipulation and is always available in memory so listeners would fire properly.

  2. Create vue instance right away but mount it in the callback of fetch.

Speaking about events being fired with 1 minute delay, socket.io stores fired events under the hood if the message wasn't processed. I suppose there is a strategy to retry processing or something like history but I'm not completely sure. There was an update recently and they might have introduced this functionality. Anyway you shouldn't dig the library that deep since it's not public API and can break with even minor release

Thank you for your response @probil .

I have tried your first suggestion but that did not work. Same behaviour, events are being executed with a minute delay. 2. Is not applicable for that specific part but I will definitly rewrite some legacy components to use the Vuex store integration. 3. tried it and it worked for receiving events, but whatever I do, it will not send anything anymore and the internal queue of socket io is not being released. Basically, re-sending them every minute like before.

Sending in components via this.$socket.client.emit('test-ping'); is not being sent (currently observing via Network tab and on the server itself) and directly sending anything in the custom callbacks I initiate in main.js also does not work. Neither via this.$socket... or socket.emit. Additionally I noticed that internal events are no longer fired, I tested connect and disconnect.

My package.json: https://gist.github.com/pistol-whip/b91f0bceea2e4b02812f0991ae3b9035

Enabling debugging gives me this: https://gist.github.com/pistol-whip/3120eac785c313cbd0e894a5a81517ff

With extended debugging on both ends, I have noticed some weird behaviour. The client is connecting to the server twice from the same connection.

@pistol-whip Oh, I dunno what might cause this. It seems like you have several points of connection. Keep it might that Vue CLI also uses socket for a feature called Hot Module Replacement but they use sockjs under the hood.

It would be nice if you could create a public repo on github with a minimal reproduction of the issue (no need tons of dependencies, the smallest the better) so I can dig it deeper and understand what's going on. While doing so you might even spot the problem on your own :)

Without having minimal example reproducing the issue (github repo, codesandbox, anything else I can fetch locally and try on my machine) I don't see any other solution but to close the issue