-
Notifications
You must be signed in to change notification settings - Fork 93
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
Improve concurrency model using a single internal dispatch queue (close #820) #842
Improve concurrency model using a single internal dispatch queue (close #820) #842
Conversation
While I have not had time to look thoroughly at all the changes, I have a couple of thoughts:
|
9045bf7
to
5ab2545
Compare
Thank you for the suggestions @hakonk, that's super valuable! I agree with starting with one internal queue and moving the dispatch to the public interface does make a lot of sense. I have tried to accomplish this in the following way:
While I agree with your point about having a "fire and forget" async interface for the tracker, I think this can only be applied to some of the tracker APIs. Most importantly, the If you have any more feedback, please let us know, really appreciate it! |
940b0d4
to
5d2f58d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
Huge effort. This should make the tracker much safer against concurrency problems. The EventSink test improvements are nice too.
…t in public interfaces
1e97006
to
1c8b9cc
Compare
@matus-tomlein is there a timeline for this to get released? We see numerous of crashes that are likely fixed with this PR. 🙏 |
Hi @AvdLee, sorry to hear about the crashes. We have a couple of other features to finish first. We're aiming to release v6 by the end of January. |
This PR contains a refactoring of the internal classes in the tracker in order to improve concurrency (following recommendations in issue #820) and make it better handle concurrent accesses. This should help with several open bug reports: #774, #817, #816.
Generally, there are the following types of changes:
Tracker
track function
I added an option to run it synchronously (using a function parameter). I realized this was necessary because of how
Session
is implemented. If the function was run async, the foreground/background event could be tracked with already changed session instead of the session at the time the event was tracked. Btw, this is also the case on the Android tracker which has an async track method, but in that case we added this workaround in the tracker.We didn't catch this in the tests because the async behaviour was mocked by the
MockDispatchQueueWrapper
. I removed this wrapper, it's probably better not to mock the async behaviour because then we are not testing what is really happening.TrackerData
To make it easier to reason about the tracker state and pass it around, I added a new wrapper class
TrackerData
. This holds the private properties of the tracker. It doesn't protect the access to the properties, the idea is that this will only be called from the Tracker private functions or fromTrackerPayloadBuilder
(see below).The Tracker class still publishes the same properties to external classes (mainly TrackerControllerImpl) as it did before. However, it runs all the accesses on a serial dispatch queue in a sync manner.
TrackerPayloadBuilder
This is an internal class that basically extracts the payload building functions from the Tracker class. The reason for this was to make it easier to test and reason about these functions separately from the Tracker. Everything in this class is executed on the serial queue so can access the tracker data directly.
Subject
Here we just wrap access to the subject properties in a serial dispatch queue.
Session
I have added two serial dispatch queues here:
dispatchQueue
used to protect access to all session data and session updatesbackgroundUpdateQueue
to queue background and foreground updatesEmitter
I added a serial queue to protect access to the internal properties, but have also tried to make some properties immutable so that we don't have to add unnecessary protections. In particular, I made the
namespace
,networkConnection
, andeventStore
immutable. This required a change in how they are instantiated – I moved all of them to be defined in the Emitter constructor.DefaultNetworkConnection
Added a serial queue here as well to protect access to the mutable properties.
Other changes
EventSink test helper
This is just a helper in the tests to make it easier to check tracked events using plugins – instead of always defining a custom plugin as we did before, we can use this helper and be consistent in our tests.