Repository navigation
Conversation
Without a cache, subscribing to a query whose server stream was already open did nothing more, so the new subscriber waited until the server pushed a change. QueryRef now keeps the last result of the live server stream and replays it to each new listener only.
Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize the Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counterproductive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here. |
After a user switch, the WebSocket transport keeps a query's server stream open until it has reconnected as the new user, so a subscriber that joined in that window was sent the previous user's last result. QueryRef now records the auth uid with the result it keeps for late subscribers and only replays it when that uid is still current. The result is also only kept when it can be replayed, i.e. no cache is configured and the server stream is live.
Description
When no cache is configured (
cacheSettingsis null, the default), a subscriber to a query that is already live never got a first result.FirebaseDataConnect.query()returns the sameQueryReffor the same query. When its server stream is already open,subscribe()does not open another one. The server only pushes when the data changes, and the ref kept no result to send, so the new subscriber waited until the next change. A common case: route A is still mounted and subscribed to a query, then route B is pushed and subscribes to the same query. B shows a spinner until the data changes on the server.Reproduced with a unit test on a fake stream transport: subscriber A got 1 result, B got 0, and one server stream was opened.
Fix. While its server stream is live and no cache is configured,
QueryRefkeeps the last result sent to its subscribers (from the server stream or fromexecute()). When a listener attaches while the server stream is live, that result is sent to that listener only, with its originalDataSource.subscribe()now returns aStream.multithat forwards the shared broadcast stream and adds the replay to its own listener, so existing subscribers get nothing extra. It still reportsisBroadcastand can be listened to more than once.subscribe()already reads the cache and sends that result, so nothing is replayed from memory.Tests
test/src/core/ref_resubscribe_test.dart, run bymelos run test), in a newQueryRef late subscribergroup:main(Expected: ['{"v":2}'] Actual: []), passes with this change._lastResult = nullclears are removed.example/integration_test/listen_e2e.dart, run bye2e-fdcagainst the emulator): a listener added to a livelistMoviesquery gets the current result. Run locally on an Android emulator (API 36) against the Data Connect emulator: it times out onmain(B never gets a result) and passes with this change, together with the existing listen tests.Notes
_streamController = null;at the same spot in_onAllSubscribersCancelled, so expect a small merge conflict. It also covers a case this PR leaves open: twoQueryRefs for the same query created before either subscribes.Related Issues
None filed. Found in a code audit.
Checklist
///).melos run analyze) does not report any problems on my PR.Breaking Change