Description
Describe the bug
We recently have switched over to using your Segment Swift-based library (from your Objective-C library).
We have code in our app that checks whether the main thread is blocked for relatively long periods of time.
We have noticed that:
(a) flush operations take place on the main thread, and
(b) those flush operations can take significant amounts of time. E.g., > 3 seconds.
To Reproduce
Steps to reproduce the behavior:
- Turn off all networking on device. E.g., airplane mode.
- Log numerous Segment events.
- Turn networking back on on device.
- Observe that flush takes place on main thread and that main thread is blocked for a relatively long period of time.
Expected behavior
Given that the flush can take a relatively long period of time (roughly proportional to the number of events pending to be sent), I expect the flush to not take place on the main thread-- which will lock up the UI if the app is in the foreground.
Screenshots
N/A
Platform (please complete the following information):
- Library Version in use: 1.4.7
- Platform being tested: iOS
Additional context
Our app serves pilots flying aircraft and in this context the devices typically do not have a networking connection, but Segment events are logged during flights. When the pilot lands, and again has networking, Segment events get uploaded.
Questions
-
We are planning to work around this issue by using custom flush policies which directly call the flush operation (e.g., as in IntervalBasedFlushPolicy), but which wrap the flush call in use of a background thread. Do you see any problematic consequences of this strategy in terms of the broader Segment library and system? So far in initial testing it works with no problem.
-
Would you be open to a PR to change this? The simplest approach seems to me to wrap the bulk of the flush code in a block executing on a background thread. Example:
public func flush() {
// only flush if we're enabled.
guard enabled == true else { return }
DispatchQueue.global(qos: .background).async {
apply { plugin in
if let p = plugin as? EventPlugin {
p.flush()
}
}
}
}