Skip to content
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

Ensure network monitor path update handler is called on start #199

Merged
21 changes: 18 additions & 3 deletions Sources/Event Logging/TracksService.m
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ @interface TracksService ()
@property (nonatomic, strong) TracksContextManager *contextManager;
@property (nonatomic, strong) TracksDeviceInformation *deviceInformation;
@property (nonatomic, strong) nw_path_monitor_t networkMonitor;
/// The queue on which the Network framework will dispatch all the executions of the update and
/// cancel events handlers.
@property (nonatomic, strong) dispatch_queue_t networkMonitorQueue;
@property (nonatomic, strong) nw_path_t networkPath;

@property (nonatomic, readonly) NSString *userAgent;
Expand Down Expand Up @@ -317,12 +320,24 @@ - (void)startNetworkMonitor {
return;
}

__weak typeof(self) weakSelf = self;
self.networkMonitor = nw_path_monitor_create();
nw_path_monitor_set_update_handler(_networkMonitor, ^(nw_path_t _Nonnull path) {

// Create and set a queue for where the monitor can execute it's event handlers.
//
// Without one, the update handler doesn't get called when the monitor starts.
dispatch_queue_attr_t attrs = dispatch_queue_attr_make_with_qos_class(
DISPATCH_QUEUE_SERIAL,
0,
0 // The relative priority within the QOS class. Can range from 0 to -15.
);
self.networkMonitorQueue = dispatch_queue_create("com.automattic.tracks.network.monitor", attrs);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Apple's docs (and various Apple engineers) recommend using dispatch_queue_create_with_target instead to create a serial queue that will target one of the existing concurrent views, rather than creating a new root queue. Creating a root queue will usually result in a permanent thread dedicated to this queue, which is definitely overkill for this particular use case.

Bonus: if we use the target API, then I don't think we need to create the attrs above at all.

I really wish this were documented better, but it's not. It's all in WWDC videos and Twitter lore from Apple engineers.

Suggested change
self.networkMonitorQueue = dispatch_queue_create("com.automattic.tracks.network.monitor", attrs);
dispatch_queue_t utilityQueue = dispatch_get_global_queue(QOS_CLASS_UTILITY, 0);
self.networkMonitorQueue = dispatch_queue_create_with_target("com.automattic.tracks.network.monitor", DISPATCH_QUEUE_SERIAL, utilityQueue);

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bjhomer, I tried this approach but it behaved as before: When the demo app launches, the update handler block is not called.

I pushed that version to a dedicated branch if you want to play with it 2ca8b3b .

In the meantime, I applied your other suggestion and verified it works following the manual script from the PR description.

What do you think of merging this version in, so we can ship the fix in WordPress 19.5, which is scheduled for the coming Monday, and then figure out why the code that Apple recommends doesn't work?

Thanks!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mokagio I just checked out 2ca8b3b. It looks like it's missing a call to network_monitor_set_queue, which is probably why it wasn't working. I added in that call and verified that it does hit the breakpoint upon launch.

If you'd rather merge in this version, though, I'm willing to accept that.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@bjhomer 🤦‍♂️... I had a feeling I missed something, but couldn't put my finger on it.

I incorporated your suggestion and verified it worked, as you said 🎉 Thanks!

Given my track record in this PR, I dismissed your review and asked for a new one. Much appreciated 🙇‍♂️

nw_path_monitor_set_queue(self.networkMonitor, self.networkMonitorQueue);

__weak typeof(self) weakSelf = self;
nw_path_monitor_set_update_handler(self.networkMonitor, ^(nw_path_t _Nonnull path) {
[weakSelf networkPathChanged:path];
});
nw_path_monitor_start(_networkMonitor);
nw_path_monitor_start(self.networkMonitor);
}

- (void)stopNetworkMonitor {
Expand Down