-
Notifications
You must be signed in to change notification settings - Fork 320
MapboxNavigationTelemetry refactoring #3540
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
Conversation
454fd80 to
6dd137a
Compare
36bc018 to
f299e88
Compare
9a5c314 to
4c4f3ee
Compare
e7ca96c to
135b092
Compare
Guardiola31337
left a comment
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.
Amazing work here and nice test coverage @korshaknn 💪
Some comments / questions to discuss before merging here.
NavigationFeedbackEventmight sent at any time between depart and arrive/cancel.
We should allow sending feedback events after arrival.
If we
arriveto the destination or somehowcancelthe session (go to FREE_DRIVE or cancel the parent job), we don't wait for all 20postEventLocations, we post it immediately.
It's also happening with preEventLocations, right?
Also wondering if we should wait until the session is canceled or the buffers are full. If not, we have a high chance to lose locations. What do you think?
2020-10-19 16:59:27.754 10667-10667/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: collect post event locations for user feedback
2020-10-19 16:59:28.093 10667-10667/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: collect post event locations for user feedback
2020-10-19 16:59:28.409 10667-10667/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: collect post event locations for user feedback
2020-10-19 16:59:28.728 10667-10667/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: route progress state = ROUTE_COMPLETE
2020-10-19 16:59:29.722 10667-10667/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: route progress state = ROUTE_COMPLETE
2020-10-19 16:59:30.757 10667-10667/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: route progress state = ROUTE_COMPLETE
2020-10-19 16:59:31.739 10667-10667/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: route progress state = ROUTE_COMPLETE
2020-10-19 16:59:32.740 10667-10667/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: route progress state = ROUTE_COMPLETE
2020-10-19 16:59:33.785 10667-10667/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: route progress state = ROUTE_COMPLETE
2020-10-19 16:59:34.727 10667-10667/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: route progress state = ROUTE_COMPLETE
2020-10-19 16:59:35.737 10667-10667/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: route progress state = ROUTE_COMPLETE
2020-10-19 16:59:36.736 10667-10667/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: route progress state = ROUTE_COMPLETE
2020-10-19 16:59:37.815 10667-10667/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: route progress state = ROUTE_COMPLETE
2020-10-19 16:59:38.086 10667-10667/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: Navigation state is FREE_DRIVE
2020-10-19 16:59:38.086 10667-10667/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: onRoutesChanged received. Route list size = 0
2020-10-19 16:59:38.108 10667-10667/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: sessionStop
2020-10-19 16:59:38.108 10667-10667/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: handleSessionCanceled
2020-10-19 16:59:38.108 10667-10667/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: flushing eventsLocationsBuffer. Pending events = 3
2020-10-19 16:59:38.116 10667-10667/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: class com.mapbox.navigation.core.telemetry.events.NavigationFeedbackEvent event sent
2020-10-19 16:59:38.134 10667-10667/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: class com.mapbox.navigation.core.telemetry.events.NavigationFeedbackEvent event sent
2020-10-19 16:59:38.142 10667-10667/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: class com.mapbox.navigation.core.telemetry.events.NavigationCancelEvent event sent
Tried to send 3 feedback events after arrival and only 2 were flushed. Note
2020-10-19 16:59:38.108 10667-10667/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: flushing eventsLocationsBuffer. Pending events = 3
Same issue different numbers 👀
2020-10-19 17:05:32.351 22859-22859/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: collect post event locations for user feedback
2020-10-19 17:05:32.667 22859-22859/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: collect post event locations for user feedback
2020-10-19 17:05:33.671 22859-22859/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: route progress state = ROUTE_COMPLETE
2020-10-19 17:05:34.680 22859-22859/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: route progress state = ROUTE_COMPLETE
2020-10-19 17:05:35.693 22859-22859/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: route progress state = ROUTE_COMPLETE
2020-10-19 17:05:36.680 22859-22859/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: route progress state = ROUTE_COMPLETE
2020-10-19 17:05:37.662 22859-22859/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: route progress state = ROUTE_COMPLETE
2020-10-19 17:05:38.700 22859-22859/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: route progress state = ROUTE_COMPLETE
2020-10-19 17:05:39.723 22859-22859/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: route progress state = ROUTE_COMPLETE
2020-10-19 17:05:40.684 22859-22859/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: route progress state = ROUTE_COMPLETE
2020-10-19 17:05:41.680 22859-22859/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: route progress state = ROUTE_COMPLETE
2020-10-19 17:05:42.708 22859-22859/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: route progress state = ROUTE_COMPLETE
2020-10-19 17:05:43.664 22859-22859/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: route progress state = ROUTE_COMPLETE
2020-10-19 17:05:44.700 22859-22859/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: route progress state = ROUTE_COMPLETE
2020-10-19 17:05:45.685 22859-22859/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: route progress state = ROUTE_COMPLETE
2020-10-19 17:05:45.888 22859-22859/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: collect post event locations for user feedback
2020-10-19 17:05:46.155 22859-22859/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: collect post event locations for user feedback
2020-10-19 17:05:46.670 22859-22859/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: route progress state = ROUTE_COMPLETE
2020-10-19 17:05:47.686 22859-22859/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: route progress state = ROUTE_COMPLETE
2020-10-19 17:05:48.671 22859-22859/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: route progress state = ROUTE_COMPLETE
2020-10-19 17:05:49.665 22859-22859/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: route progress state = ROUTE_COMPLETE
2020-10-19 17:05:50.697 22859-22859/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: route progress state = ROUTE_COMPLETE
2020-10-19 17:05:51.671 22859-22859/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: Navigation state is IDLE
2020-10-19 17:05:51.671 22859-22859/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: MapboxNavigation onDestroy
2020-10-19 17:05:51.809 22859-22909/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: master job canceled
2020-10-19 17:05:51.809 22859-22909/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: sessionStop
2020-10-19 17:05:51.810 22859-22909/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: handleSessionCanceled
2020-10-19 17:05:51.810 22859-22909/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: flushing eventsLocationsBuffer. Pending events = 4
2020-10-19 17:05:51.821 22859-22909/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: class com.mapbox.navigation.core.telemetry.events.NavigationFeedbackEvent event sent
2020-10-19 17:05:51.844 22859-22909/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: class com.mapbox.navigation.core.telemetry.events.NavigationFeedbackEvent event sent
2020-10-19 17:05:51.850 22859-22909/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: class com.mapbox.navigation.core.telemetry.events.NavigationCancelEvent event sent
This was closing the activity (pressing back button) previous one was clicking on CLEAR ROUTES. Sent 4 feedback events 👀
2020-10-19 17:05:51.810 22859-22909/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: flushing eventsLocationsBuffer. Pending events = 4
2020-10-19 17:05:51.821 22859-22909/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: class com.mapbox.navigation.core.telemetry.events.NavigationFeedbackEvent event sent
2020-10-19 17:05:51.844 22859-22909/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: class com.mapbox.navigation.core.telemetry.events.NavigationFeedbackEvent event sent
2020-10-19 17:05:51.850 22859-22909/com.mapbox.navigation.examples D/MAPBOX_TELEMETRY: class com.mapbox.navigation.core.telemetry.events.NavigationCancelEvent event sent
It says pending events 4 and only 2 were sent 🤔
Can we add a test for that?
Currently (AFAIK), in case we have a route with multiple way points we don't send a DEPART and CANCEL event at each pair of waypoints.
This is not supported at the moment. We should figure how to solve as we're not calling setRoute 🤔
Is #2748 going to be addressed as part of this PR? It'd be great to have a test for that.
| // TODO:OZ voiceIndex is not available in SDK 1.0 and was not set in the legacy telemetry navigationEvent.voiceIndex | ||
| // TODO:OZ bannerIndex is not available in SDK 1.0 and was not set in the legacy telemetry navigationEvent.bannerIndex |
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.
Are these TODOs fixed?
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.
I don't know what to do with it.
There are no voiceIndex or bannerIndex properties in the model classes.
Looks like can be removed.
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.
Lines 66 to 67 in a3dfcaa
| var voiceIndex: Int = 0 | |
| var bannerIndex: Int = 0 |
Lines 369 to 383 in e232efd
| int getVoiceIndex() { | |
| return voiceIndex; | |
| } | |
| void setVoiceIndex(int voiceIndex) { | |
| this.voiceIndex = voiceIndex; | |
| } | |
| int getBannerIndex() { | |
| return bannerIndex; | |
| } | |
| void setBannerIndex(int bannerIndex) { | |
| this.bannerIndex = bannerIndex; | |
| } |
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.
yep, NavigationEvent has such fields, but what data should be used to init them?
something from RouteProgress?
| override var firstLocation: Location? = null | ||
| override var routeProgress: RouteProgress? = null | ||
| override var originalRoute = CompletableDeferred<DirectionsRoute>() | ||
| private val mutex = Mutex() |
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.
Do we really need this Mutex?
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.
yes. we remove items with iterator and it should be synchronized. fun is suspend, so Mutex is used for synchronization.
private suspend fun accumulatePostEventLocation(location: Location) {
mutex.withLock {
val iterator = eventsLocationsBuffer.iterator()
while (iterator.hasNext()) {
iterator.next().let {
it.addPostEventLocation(location)
if (it.postEventLocationsSize() >= LOCATION_BUFFER_MAX_SIZE) {
it.onBufferFull()
iterator.remove()
}
}
}
}
}
...ion-core/src/test/java/com/mapbox/navigation/core/telemetry/MapboxNavigationTelemetryTest.kt
Outdated
Show resolved
Hide resolved
...test/java/com/mapbox/navigation/core/telemetry/TelemetryLocationAndProgressDispatcherTest.kt
Outdated
Show resolved
Hide resolved
we can do it, but it will break the order. Right now all feedback events will be between depart-arrive, so we have chronological order. If we allow to send it after arrival order will be broken.
no, we always take
It depends on:
I've retested it many times in different scenarios. Everything works fine. Are you using the latest commit? let's discuss all |
|
Discussed internally.
That's currently an option. In any case, we're going to keep track of the
so the sending order won't be a problem.
See comment above:
See comment above. If we keep track of the creation time, order in which events are pushed shouldn't be an issue. We can keep pushing depart, arrive and cancel events immediately and push feedback and reroute ones afterwards (with the logic above-mentioned).
This is still reproducible. We should investigate further and fix.
Sounds good 👍 |
Guardiola31337
left a comment
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.
Is it safe to remove internal TelemetryEvent and SessionState? It seems so.
it was unused |
We should remove them then 😅 |
1e9cc0d to
7bb35c1
Compare
LukasPaczos
left a comment
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.
Fantastic work @korshaknn!
...ion-core/src/test/java/com/mapbox/navigation/core/telemetry/MapboxNavigationTelemetryTest.kt
Outdated
Show resolved
Hide resolved
| } | ||
|
|
||
| @Test | ||
| fun feedback_and_reroute_events_not_sent_on_arrival() = runBlocking { |
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.
Why should we not send those events on arrival?
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.
Also wondering if we should wait until the session is canceled or the buffers are full. If not, we have a high chance to lose locations.
try to collect as much as
preEventLocationsandpostEventLocationsas possible (if the queues are full, feedback / reroute events will be sent immediately) and only flush the pending events (as is i.e.preEventLocationsandpostEventLocationscollected until that moment) if:
- the session is canceled
- the parent job is canceled
- a new route is set
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.
What happens if the user arrives and force-closes the app without going to free-drive? Are we going to lose the events?
I think that would be too big of a risk to rely on developers to go to free-drive after arriving or to wait for the buffer to fill up in order to receive the events. I'd personally rather lose some post-event location samples than the whole event.
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.
no no, everything will be ok. it will be handled by parentJob listener.
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.
What happens if the user arrives and force-closes the app without going to free-drive? Are we going to lose the events?
Nah, if that happens, all pending events are sent immediately.
only flush the pending events (as is i.e.
preEventLocationsandpostEventLocationscollected until that moment) if:
- the session is canceled
- the parent job is canceled
- a new route is set
Does that make sense? If the implementation is not behaving like that, then definitely is a bug that we need to fix.
cc @korshaknn
| callbackDispatcher.onOffRouteStateChanged(true) | ||
| callbackDispatcher.onOffRouteStateChanged(false) | ||
| callbackDispatcher.onRoutesChanged(routes) |
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.
Should this race be resolved in the core module?
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.
what do you mean?
we use it to simulate behavior and test some flow
| callbackDispatcher.onRoutesChanged(routes) | ||
| assertEquals(route, (callbackDispatcher.newRouteChannel.receive() as ExternalRoute).route) |
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.
Is this correct? Since we are still not on the route (at least Nav Native doesn't think we are), shouldn't this be considered a reroute-route?
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.
it depends on onOffRouteStateChanged.
if it was called with offRoute==true, we will use the next new route as RerouteRoute, or ExternalRoute otherwise
...main/java/com/mapbox/navigation/core/telemetry/TelemetryLocationAndProgressDispatcherImpl.kt
Outdated
Show resolved
Hide resolved
...igation-core/src/main/java/com/mapbox/navigation/core/telemetry/MapboxNavigationTelemetry.kt
Outdated
Show resolved
Hide resolved
|
It seems |
|
Noticed that we're trying to send cancel and then send an incorrect depart when selecting an alternative route but the session hasn't started 👀 We should make sure that events are only pushed when in Active Guidance. |
|
we can get a new route after:
if we use |
|
Couldn't we have that logic irrespective of the state but only send the events if the session has started? We had |
e349c71 to
8e3c78f
Compare
|
@LukasPaczos @Guardiola31337 ready for the next round |
|
Noticed that we're trying to send a
|
|
Took latest changes for a spin and all the tests cases / scenarios run were successful 🎉 Great work removing Coroutines / Let's work on tests and the tailwork 🚀 |
Guardiola31337
left a comment
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.
Run some tests and so far it's working as expected 🚀
Left some minor comments / questions.
...igation-core/src/main/java/com/mapbox/navigation/core/telemetry/MapboxNavigationTelemetry.kt
Outdated
Show resolved
Hide resolved
...igation-core/src/main/java/com/mapbox/navigation/core/telemetry/MapboxNavigationTelemetry.kt
Show resolved
Hide resolved
...igation-core/src/main/java/com/mapbox/navigation/core/telemetry/MapboxNavigationTelemetry.kt
Outdated
Show resolved
Hide resolved
...ion-core/src/test/java/com/mapbox/navigation/core/telemetry/MapboxNavigationTelemetryTest.kt
Show resolved
Hide resolved
| return this.apply { | ||
| sdkIdentifier = this@MapboxNavigationTelemetry.sdkIdentifier | ||
|
|
||
| routeProgress!!.let { routeProgress -> |
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.
Should we check for routeProgress and originalRoute first to populate all the data? Wondering if we could run into a situation in which routeProgress and originalRoute are null but the event is sent with missing / partial data 🤔
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.
no need to check it.
NavigationEvent.populate() can be called only if the session is started.
And session can be started when routeProgress and originalRoute are not null.
Wondering if we could run into a situation in which routeProgress and originalRoute are null but the event is sent with missing / partial data 🤔
if any of them is null we will have a crash, no event will be sent.
...igation-core/src/main/java/com/mapbox/navigation/core/telemetry/MapboxNavigationTelemetry.kt
Show resolved
Hide resolved
...ion-core/src/test/java/com/mapbox/navigation/core/telemetry/MapboxNavigationTelemetryTest.kt
Outdated
Show resolved
Hide resolved
07473c5 to
4569b57
Compare
Guardiola31337
left a comment
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.
Thanks for addressing the feedback @korshaknn
Great great work 💪
Let's merge here and follow up with any tailwork in separate future PRs 🚀
Description
Let's simplify code inside
TelemetryLocationAndProgressDispatcherandMapboxNavigationTelemetryHow it works:
MapboxNavigationTelemetryis used to postNavigationEvent.NavigationAppUserTurnstileEventis sent whenMapboxNavigationTelemetryis initializedNavigationDepartEventis sent when session state changes toACTIVE_GUIDANCENavigationRerouteEventis sent after rerouteNavigationArriveEventis sent after arrivalNavigationCancelEventis sent when session state changes toFREE_DRIVEorIDLE, or when parent job is canceled.NavigationFeedbackEventmight sent at any time between depart and arrive/cancel.To populate event with data,
TelemetryLocationAndProgressDispatcheris used. It provides all needed data such asoriginal/new route,routeProgress,location, etc.All events are sent immediately, but
NavigationRerouteEventandNavigationFeedbackEventare pending. It means that we need a list of locationsbeforeandaftereach event.TelemetryLocationAndProgressDispatchercaches the most recent locations. Max size of the cache is20.When any of pending events is fired, we get the cache and copy it to the event as
preEventLocationsand start to collectpostEventLocations. When it reaches the max size (20items) we send pending event.In perfect situation pending event will have
20locations before event and20locations after.If we
arriveto the destination or somehowcancelthe session (go to FREE_DRIVE or cancel the parent job), we don't wait for all 20postEventLocations, we post it immediately.The base flow
NavigationAppUserTurnstileEventNavigationDepartEventfeedback->NavigationFeedbackEventis not sent, collect locations, when ready -> sendfeedback->NavigationFeedbackEventis not sent, collect locations, when ready -> sendfeedback->NavigationRerouteEventis not sent, collect locations, when ready -> sendNavigationArriveEventIf we set a new route externally, we send all pending events, send
NavigationCancelEventandNavigationDepartEventTesting
Please describe the manual tests that you ran to verify your changes
SNAPSHOTupstream dependencies if needed) through testapp/demo app and run all activities to avoid regressionsChecklist
CHANGELOGincluding this PRapi/current.txtfiles after running$> make core-update-api(Core) /$> make ui-update-api(UI) if there are changes / errors we're 🆗 with (e.g.AddedMethodchanges are marked as errors but don't break SemVer) 🚀 If there are SemVer breaking changes add theSEMVERlabel. See Metalava docs