-
-
Notifications
You must be signed in to change notification settings - Fork 58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Realtime websocket loses connection regularly when browser tab goes to background #121
Comments
Just want to add it is understood by me, and should be understood or made clear to users of real-time, the need to monitor the subscribe and take appropriate action if the subscription fails. The reason I dug into how to watch the subscribe status is I use it as part of my online/offline logic and reload message counts when coming back online. But my overhead is such that doing this with a background tab every 3 minutes is very costly. I’ve already started down the path to use the visibility hook to not reload if hidden but it will still be painful if the user is just moving thru tabs on his screen and goes away fo 10 minutes. |
Looking into this more I see realtime uses websocket-node. I'm hopeful there are some settings that can deal with the background tab throttle giving client more time to ping. I've found no discussions on that particular package but here are others that have had to deal with this: |
I see that you're using Phoenix. We're having similar issues with the websocket disconnecting after a while – mostly in an inactive browser tab. |
Adding this comment here also on Chrome and going to 1 minute timeouts (which would break the 60 sec heartbeat).
https://developer.chrome.com/blog/timer-throttling-in-chrome-88/ |
Not directly related to the above issue (which is still there). @w3b6x9 I'm not sure who at Supabase is the knowledge keeper of the phoenix realtime socket level stuff... But I think it is important to understand what level of interruption a websocket can have and still have the server maintain an output queue of realtime changes to that socket. This is important in determining when to reload a dataset because changes could have been missed. |
@GaryAustin1 if the server doesn't receive a heartbeat for 60 seconds (this is the default for all Supabase projects running Realtime RLS but can be customized) then it will sever the socket connection. When the socket connection is severed, all of the channel processes (every topic that a client was listening to via the socket conn) dies. On reconnect, all of the topics that the client is listening to will join as new channel processes on the server. |
@w3b6x9 Unfortunately the code is somewhat custom for each case of a subscription depending on table size (do you want just last x entries or whole table), the id column for keeping the "table" array updated, inserts at beginning or end and filter. I tried to push that code into an update handler. |
EDIT: Add link |
This hasn't been solved yet ? |
@xxholyChalicexx we have not visited this issue yet but will investigate in the near future. Is this currently blocking you? Have you come up with alternatives? |
well its not blocking but it gets annoying at times. As of now i try to catch and reconnect, i do that so that too is hit and a miss. Thankfully it doesnt have any adverse effect so for now just making it work. |
I just wanted to check in and see if there was any movement here?! |
We'll be implementing a solution for this in the next few weeks. |
Has the solution been implemented? |
Interested in this as well because I'm also seeing disconnects on inactive tabs and it causes the client to not receive changes from the DB which in turn places the client out of sync with the rest of the participants |
@netgfx, The flow chart here might be a bit dated supabase/supabase#5641 but shows a general idea. |
I have the same problem as OP and want to express my support for fixing this issue. |
Struggling with the same issue. I thought this was a rather easy fix? |
I'm currently having this issue. I'm using the NextJs clients and tried to play around with the realtime options e.g. |
The problem is the timers get throttled by the browser and not much works that relies on timer, if it is the background or powerdown mode of a mobile device. |
Could the connection be monitored by a web worker? That would solve the throttle or backgrounded tab issue |
i have the same problem. With latest version of Chrome on win11, the channel-connection dies and no more updates are received |
same issue here |
@w3b6x9 Is this solution implemented? I am still seeing the disconnection issue when the tab is not used for a while unfortunately.. |
We've been struggling with same issue for a while and have found a solution that's working for us by disconnecting from the realtime channel whenever the tab is hidden and reconnecting when the tab is visible. Here's how we are doing it (app is in Svelte):
|
the above seems like a good solution. If the disconnection is an issue due to browser pausing the tab then perhaps this operation (to keep the connection alive) should be offloaded to a webworker that is never paused by default 🤔 |
Sure that could be a way to go, although offering too many options could be confusing. The other option would be to add an example to the docs on how to use this technique to bypass CORS restrictions and let the users implement it at will, it is not that complex either just a couple of lines of code. |
probably the option of building the blob from the url is really the best will tackle that |
Does the same happen when loading the worker script from a CDN like supabase storage (public) or unpkg.
so I think loading the worker from a CDN is the norm for this type of functionalities |
opened PR with your suggestion (as discussed in Discord) and works really well 🔥 |
FYI PR has been merged - https://www.npmjs.com/package/@supabase/realtime-js/v/2.10.5-next.2 - |
@filipecabaco I can confirm it works out of the box on codesandbox with minimal configuration:
|
way better and more elegant! thank you again for finding this approach @netgfx |
URL.createObjectURL is only available in a browser environment, if you are using this library via nodejs I don't think this solution will work. You can check via:
But if you are using it via nodejs you shouldn't need to use the worker, because nodejs connection shouldn't drop, the issue of this post happens because the browser throttles javascript execution and the websocket connection closes after a while. |
this 👍 for node environments I would not advice to use web workers as they are not properly supported but the screenshot is from a browser. @appelmoesje could you details which version and which browser are you using? |
@filipecabaco @netgfx I'm using it in a Chrome Extension background script so it does not have the browser context. |
I'm currently using export const realtimeClient = new RealtimeClient(
"wss://URL/realtime/v1",
{
worker: true,
workerUrl: chrome.runtime.getURL('/assets/js/worker.js'),
heartbeatIntervalMs: 15000,
logger: console.log,
params: {
apikey: process.env.PLASMO_PUBLIC_SUPABASE_ANON_KEY,
},
}
); |
@appelmoesje does the same error occur if you completely remove the |
this seems to be a bigger issue because of Chrome Extensions ways of work ( https://www.reddit.com/r/learnjavascript/comments/18t42ic/stuck_on_trying_to_download_a_blob_for_chrome/ ) Maybe you can encode the content as a base64 blob and send it via |
I think i found a solution for my case. The code below i added to the background worker. This seems to work for now. chrome.alarms.onAlarm.addListener(() => {
console.log('Alarm triggered, keeping the service worker alive.');
setupSupabaseChannel();
});
chrome.alarms.create('keep-alive', { periodInMinutes: 0.1 }); |
@appelmoesje nice! yeah since chrome extensions are workers you can just capture and send the event 👍 |
FWIW, my connection is dying / getting a TIMED_OUT on Node. |
@njoshi22 could you try reduce the heartbeat time to 20 seconds? |
I tried and deployed to a k8s cluster (with persistent connection), still timed out. I was planning on having a server that listened to realtime and then triggered notifications, looks like I won't be able to do that now without relying on Debezium or another external library, given how unpredictable these time outs are. |
I think this is from an unrelated issie, try lower the heartbeat to 25 seconds and check if it still persists. Currently I suspect that the default 30s is killing the connection somewhere but I'm still investigating |
Hmm - yeah I made it to 15s per your suggestion above. Happy to help debug further! |
I'm having realtime disconnection issues as well, but I'm using the JS Client Library. When I try that code in Chrome Console for instance, I get "Uncaught ReferenceError: RealtimeClient is not defined". Any idea what I can do? Thanks! |
Realtime client is imported like this: |
Bug report
Describe the bug
With a simple subscription to a table (RLS or Not) the websocket drops and reconnects every 3 minutes after 5 minutes of tab in background. Verifying on Windows 10 with Chrome and Edge. Note going to different tab on browser puts other tabs in background mode.
To Reproduce
var supabase = supabase.createClient("https://url.supabase.co", "auth code")
let mySubscription = supabase
.from('status')
.on('*', payload => {
console.log('Change received!', payload)
})
.subscribe((status,e)=>{
console.log('subscribe status,error',status,e);
})
Start up subscription to a table. Start Dev Console turn on networking and timestamps. Shrink browser or hide tab under others. Wait >10 minutes.
Websocket will have disconnected and connected several times.
This is a pretty bad condition for real-time if it is to be relied on at all for more than the current active window time. During each disconnect changes to the table would be missed.
It is also compounded that Supabase does not really document error and close handlers for realtime subscription at supabase.js or higher. Only here in the realtime.js description do you see error handlers. It took looking at the supabase.js code to see that one could do .subscribe((status,error)=>{console.log(status,error)} to see connection failures. OTHERWISE THIS IS A SILENT FAILURE AS THE SUBSCRIPTION KEEPS RUNNING EVEN THOUGH DROPPING POTENTIAL UPDATES. Anytime realtime drops the socket, if you want reliable data you have to reload from your tables to get all recent changes.
Expected behavior
The websocket should remain alive even when tab/window is hidden and in background mode. Realtime.js must understand different timings done by background throttle of browsers and keep connection alive.
Screenshots
Below is about 15 minutes after leaving browser in background...
System information
Windows 10
supabase.js 1.28.5
Chrome or Edge
Additional context
Out of time for a few days but I'll try and get more info on these additional issues.
EDIT: I no longer believe there is an error with multiple connections for a single user.
Further investigation posted in my next issue points to a more general realtime.js bug on losing the refreshed token on a disconnect/reconnect of the websocket for any reason (the above being one).
The text was updated successfully, but these errors were encountered: