supabase: Realtime does not emit all events

Bug report

Describe the bug

In the network tab the websocket message comes in. But the event handler does not work properly. Sometimes it works and sometimes the listener won’t get called.

To Reproduce

It’s very hard to reproduce and I don’t know how to debug it because it only appears sometimes. I can’t descibe it properly. My code is this:

useEffect(() => {
    if (!selectedProfile) {
      return () => {};
    }
    const todayMinus15Days = new Date();
    todayMinus15Days.setDate(todayMinus15Days.getDate() - 15);

    supabase
      .from<{ count: number; user_id: string }>('counts')
      .select('count')
      .eq('user_id', selectedProfile!)
      .then(({ data }) => {
        const counts = data ?? [];
        if (counts.length === 1) {
          const first = counts[0].count;
          setCount(first);
        } else {
          supabase
            .from('counts')
            .insert({ count: 0, user_id: selectedProfile })
            .then();
        }
      });

    supabase
      .from('rules')
      .select()
      .eq('user_id', selectedProfile)
      .order('points')
      .then(({ data }) => setRules(data ?? []));

    supabase
      .from('events')
      .select()
      .order('created_at', { ascending: false })
      .eq('user_id', selectedProfile)
      .gt('created_at', todayMinus15Days.toISOString())
      .then(({ data }) => setEvents(data ?? []));

    supabase
      .from('profiles')
      .select()
      .then(({ data }) =>
        setProfiles((data ?? []).filter((p) => !!p.first_name)),
      );

    const updateSubscription = supabase
      .from('*')
      .on('INSERT', (payload) => {
        if (payload.new.user_id !== selectedProfile) {
          return;
        }
        switch (payload.table) {
          case 'rules': {
            setRules((rules) => [...rules, payload.new]);
            break;
          }
          case 'events': {
            setEvents((events) => {
              const newEvents = [...events, payload.new];
              newEvents.sort(
                (a, b) =>
                  new Date(b.created_at).getTime() -
                  new Date(a.created_at).getTime(),
              );
              return newEvents;
            });
            break;
          }
          case 'counts': {
            setCount(payload.new.count);
            break;
          }
        }
      })
      .on('DELETE', (payload) => {
        switch (payload.table) {
          case 'rules': {
            setRules((rules) =>
              rules.filter((rule) => rule.id !== payload.old.id),
            );
            break;
          }
          case 'events': {
            setEvents((events) =>
              events.filter((event) => event.id !== payload.old.id),
            );
            break;
          }
        }
      })
      .on('UPDATE', (payload) => {
        if (payload.new.user_id !== selectedProfile) {
          return;
        }
        switch (payload.table) {
          case 'rules': {
            setRules((rules) => {
              const idx = rules.findIndex((rule) => rule.id === payload.old.id);
              const newRules = [...rules];
              newRules[idx] = payload.new;
              return newRules;
            });
            break;
          }
          case 'events': {
            setEvents((events) => {
              const idx = events.findIndex(
                (event) => event.id === payload.old.id,
              );
              const newEvents = [...rules];
              newEvents[idx] = payload.new;
              return newEvents;
            });
            break;
          }
          case 'counts': {
            setCount(payload.new.count);
            break;
          }
        }
      })
      .subscribe();

    return () => {
      updateSubscription.unsubscribe();
    };
  }, [selectedProfile]);

Expected behavior

It should work always…

System information

  • OS: Android; Windows
  • Browser (if applies) chrome
  • Version of supabase-js: 1.29.2
  • Version of Node.js: 16

About this issue

  • Original URL
  • State: closed
  • Created 2 years ago
  • Comments: 19 (12 by maintainers)

Most upvoted comments

@danieldaeschle will close this issue. Feel free to reopen if you want to investigate again.

@w3b6x9 There is definitely something strange going on with latest code. (I went back to 1.29.3 and restarted supabase and same issue).

I have a test setup that runs an anon subscription to a two column no RLS table. I run this on a networked server so I can run from many different devices, but in this case just using 1 windows/firefox browser tab that has always worked (even in background).

I have another program running just doing an update of the count column every 30 seconds.

log

I’ve never seen subscription errors in firefox tab before (but I’ve never run 30second updates either). You can see in log one of the 30second updates got missed in the connection reset.

connect close

You can see heartbeat just seems to stop.

WHEN I STOP THE 30 SECOND UPDATE LOOP THE SUBSCRIPTION RUNS AS NORMAL!

normal

Turning back on the update loop, breaks again:

breaksagain

Code: code

pollcode

@danieldaeschle Besides, w3b6x9’s suggestion, you can put an error handler in subscribe like:

.subscribe((status)=>{console.log('subscribe status = ',status);})

And see if subscription is stable.

Also are you seeing just one websocket, or several after awhile? If you lose connection you would have a new websocket for each reconnect, but still a “good” subscription if you don’t look at status, as it retries during breaks (but does not track data during break) and reconnects.

@danieldaeschle supabase-js v1.29.2 enforces unique subscriptions and there may be some weirdness with just calling unsubscribe() during cleanup. Make sure you’re using removeSubscription or removeAllSubscriptions to properly clean up the subscription on unmount:

supabase.removeSubscription(updateSubscription)