How to obtain reliable realtime updates in the real world. #5641
Replies: 8 comments 22 replies
-
I've implemented the above flowchart and done limited testing using this code structure.
This yields the following when run in Chrome tab that errors after 5 minutes hidden. |
Beta Was this translation helpful? Give feedback.
-
Started working on an update to this for current realtime and also adding in how to deal with issues of getting reliable data at start up... |
Beta Was this translation helpful? Give feedback.
-
Hello ! May somebody help me to know what to do when Status === Closed ? Thank you |
Beta Was this translation helpful? Give feedback.
-
Was this already addressed? I am seeing this comment here and I am confused. |
Beta Was this translation helpful? Give feedback.
-
Hi all - I've just released Supabase Live Table. The algorithm is similar to what @GaryAustin1 has implemented - subscribing before requesting a snapshot is pretty standard in trading software. I've also added additional reconciliation logic based on timestamps. During reconciliation we can decide to discard a message, or emit an error if we detect an anomaly. You can see some sequence diagrams here - they are generated from the unit tests. By decoupling the reconciler from the networking layer, I can unit test the reconciler by just firing messages at it. If anyone finds a bug, reproducing it in this test suite is a good place to start. We've been using this in production at Open Art Market for a while now, and it's worked well for us. |
Beta Was this translation helpful? Give feedback.
-
I believe I have handled all the cases you describe. The tricky bit is with update events, and whether to ignore them or process them. There are two things to consider:
Whether the event arrives before or after the snapshot should not affect the outcome. There are 4 scenarios to consider here: replays updates that are more recent than snapshot and arrived aftersequenceDiagram
LiveTable->>+Supabase: subscribe
Supabase->>-LiveTable: subscription active
LiveTable->>+Supabase: get snapshot
Supabase->>-LiveTable: snaphot: [{"id":1,"created_at":"1","updated_at":"2","name":"Bicycle","type":"vehicle"}]
Supabase-->>LiveTable: UPDATE {"id":1,"created_at":"1","updated_at":"3","name":"Bike","type":"vehicle"}
replica[
{
"id": 1,
"created_at": "1",
"updated_at": "3",
"name": "Bike",
"type": "vehicle"
}
] replays updates that are more recent than snapshot and arrived beforesequenceDiagram
LiveTable->>+Supabase: subscribe
Supabase->>-LiveTable: subscription active
LiveTable->>+Supabase: get snapshot
Supabase-->>LiveTable: UPDATE {"id":1,"created_at":"1","updated_at":"3","name":"Bike","type":"vehicle"}
Supabase->>-LiveTable: snaphot: [{"id":1,"created_at":"1","updated_at":"2","name":"Bicycle","type":"vehicle"}]
replica[
{
"id": 1,
"created_at": "1",
"updated_at": "3",
"name": "Bike",
"type": "vehicle"
}
] skips updates that predate the snapshot and arrive aftersequenceDiagram
LiveTable->>+Supabase: subscribe
Supabase->>-LiveTable: subscription active
LiveTable->>+Supabase: get snapshot
Supabase->>-LiveTable: snaphot: [{"id":1,"created_at":"1","updated_at":"3","name":"Bicycle","type":"vehicle"}]
Supabase-->>LiveTable: UPDATE {"id":1,"created_at":"1","updated_at":"2","name":"Bike","type":"vehicle"}
replica[
{
"id": 1,
"created_at": "1",
"updated_at": "3",
"name": "Bicycle",
"type": "vehicle"
}
] skips updates that predate the snapshot and arrive beforesequenceDiagram
LiveTable->>+Supabase: subscribe
Supabase->>-LiveTable: subscription active
LiveTable->>+Supabase: get snapshot
Supabase-->>LiveTable: UPDATE {"id":1,"created_at":"1","updated_at":"2","name":"Bike","type":"vehicle"}
Supabase->>-LiveTable: snaphot: [{"id":1,"created_at":"1","updated_at":"3","name":"Bicycle","type":"vehicle"}]
replica[
{
"id": 1,
"created_at": "1",
"updated_at": "3",
"name": "Bicycle",
"type": "vehicle"
}
] |
Beta Was this translation helpful? Give feedback.
-
If you don't look at timestamps, how do you decide whether or not to apply an event? If you apply them regardless, you will end up with an incorrect replica. See the two "skips updates..." examples. Look at the value of |
Beta Was this translation helpful? Give feedback.
-
Let's consider this example: sequenceDiagram
LiveTable->>+Supabase: subscribe
Supabase->>-LiveTable: subscription active
LiveTable->>+Supabase: get snapshot
Supabase->>-LiveTable: snaphot: [{"id":1,"created_at":"1","updated_at":"3","name":"Bicycle","type":"vehicle"}]
Supabase-->>LiveTable: UPDATE {"id":1,"created_at":"1","updated_at":"2","name":"Bike","type":"vehicle"}
Would you agree that applying this |
Beta Was this translation helpful? Give feedback.
-
I've been looking at the reliability of Supabase realtime for awhile and conclude that just doing the standard examples of starting a subscription and letting realtime handle re-connections in the background will cause loss of data changes. When faced with a lost connection or heartbeat the realtime code attempts to reconnect and resume BUT loses any updates on server during this time.
You have to put an error monitor in .subscribe() to see these connection errors (the payload portion of the code will look fine because of the reconnect attempts realtime is doing):
.subscribe((status) => {console.log('status - ', status)})
After testing on several browsers on a Windows desktop as well as mobile devices with (Safari and Chrome) it becomes clear subscriptions are lost in all cases (except Firefox on Windows) when the tab running realtime is not in focus, or device goes to sleep. Of course loss of internet connection even briefly can cause the same issue. Basic realtime examples in Supabase docs will all look like they are running normally when tab returns.
I'm looking at the following flow to be able to use realtime reliably (never miss a subscribed database change).
At first I was going to just use visibility of the page, but then if you just tab away from a page for a minute, you have to reload all your monitored realtime data.
There are other approaches in addition to above using timestamps that might reduce amount of data needing to be refreshed.
Here are some examples of realtime in background/sleeping tabs:
Windows Edge (Chrome is similar) on background tab:
iPad/Safari:
Note in this case the device goes to sleep and errors from earlier in time show up after tab comes back.
Android/Chrome (note results differ between powered and battery operation, but all still lose subscription in time):
Beta Was this translation helpful? Give feedback.
All reactions