diff --git a/CHANGELOG.md b/CHANGELOG.md index 0430518bd5f..3e40340e56f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ ## Unreleased +### Fixes + +- Uses low-priority queues to reduce the chance of session replay internal multi-threading processes being dropped (#5280) + ### Improvements - Threading issues in internal dependency container (#5225) diff --git a/Sources/Sentry/SentryDispatchFactory.m b/Sources/Sentry/SentryDispatchFactory.m index 7ec41369f8e..168759397ec 100644 --- a/Sources/Sentry/SentryDispatchFactory.m +++ b/Sources/Sentry/SentryDispatchFactory.m @@ -11,13 +11,16 @@ - (SentryDispatchQueueWrapper *)queueWithName:(const char *)name return [[SentryDispatchQueueWrapper alloc] initWithName:name attributes:attributes]; } -- (SentryDispatchQueueWrapper *)createBackgroundQueueWithName:(const char *)name - relativePriority:(int)relativePriority +- (SentryDispatchQueueWrapper *)createLowPriorityQueue:(const char *)name + relativePriority:(int)relativePriority { SENTRY_CASSERT(relativePriority <= 0 && relativePriority >= QOS_MIN_RELATIVE_PRIORITY, @"Relative priority must be between 0 and %d", QOS_MIN_RELATIVE_PRIORITY); + // The QOS_CLASS_UTILITY is defined in `qos.h` and used by the `DISPATCH_QUEUE_PRIORITY_LOW`, + // therefore it can be considered it a low priority queue + // Reference: https://developer.apple.com/documentation/dispatch/dispatch_queue_priority_low dispatch_queue_attr_t attributes = dispatch_queue_attr_make_with_qos_class( - DISPATCH_QUEUE_SERIAL, QOS_CLASS_BACKGROUND, relativePriority); + DISPATCH_QUEUE_SERIAL, QOS_CLASS_UTILITY, relativePriority); return [[SentryDispatchQueueWrapper alloc] initWithName:name attributes:attributes]; } diff --git a/Sources/Sentry/SentrySessionReplayIntegration.m b/Sources/Sentry/SentrySessionReplayIntegration.m index df67ad4cd4c..c8babe8dace 100644 --- a/Sources/Sentry/SentrySessionReplayIntegration.m +++ b/Sources/Sentry/SentrySessionReplayIntegration.m @@ -143,14 +143,14 @@ - (void)setupWith:(SentryReplayOptions *)replayOptions // The asset worker queue is used to work on video and frames data. // Use a relative priority of -1 to make it lower than the default background priority. _replayAssetWorkerQueue = - [dispatchQueueProvider createBackgroundQueueWithName:"io.sentry.session-replay.asset-worker" - relativePriority:-1]; + [dispatchQueueProvider createLowPriorityQueue:"io.sentry.session-replay.asset-worker" + relativePriority:-1]; // The dispatch queue is used to asynchronously wait for the asset worker queue to finish its // work. To avoid a deadlock, the priority of the processing queue must be lower than the asset // worker queue. Use a relative priority of -2 to make it lower than the asset worker queue. _replayProcessingQueue = - [dispatchQueueProvider createBackgroundQueueWithName:"io.sentry.session-replay.processing" - relativePriority:-2]; + [dispatchQueueProvider createLowPriorityQueue:"io.sentry.session-replay.processing" + relativePriority:-2]; // The asset worker queue is used to work on video and frames data. diff --git a/Sources/Sentry/include/SentryDispatchQueueProviderProtocol.h b/Sources/Sentry/include/SentryDispatchQueueProviderProtocol.h index 7b8bf017241..dc6ddfd1ea1 100644 --- a/Sources/Sentry/include/SentryDispatchQueueProviderProtocol.h +++ b/Sources/Sentry/include/SentryDispatchQueueProviderProtocol.h @@ -13,7 +13,7 @@ NS_ASSUME_NONNULL_BEGIN attributes:(dispatch_queue_attr_t)attributes; /** - * Creates a background queue with the given name and relative priority, wrapped in a @c + * Creates a low priority queue with the given name and relative priority, wrapped in a @c * SentryDispatchQueueWrapper. * * @note This method is only a factory method and does not keep a reference to the created queue. @@ -25,8 +25,8 @@ NS_ASSUME_NONNULL_BEGIN * quality-of-service. * @return Unretained reference to the created queue. */ -- (SentryDispatchQueueWrapper *)createBackgroundQueueWithName:(const char *)name - relativePriority:(int)relativePriority; +- (SentryDispatchQueueWrapper *)createLowPriorityQueue:(const char *)name + relativePriority:(int)relativePriority; @end diff --git a/Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift b/Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift index 89e92f54f4f..bcac44b2ca7 100644 --- a/Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift +++ b/Tests/SentryTests/Integrations/SessionReplay/SentrySessionReplayIntegrationTests.swift @@ -650,10 +650,10 @@ class SentrySessionReplayIntegrationTests: XCTestCase { // -- Assert -- XCTAssertEqual(assetWorkerQueue.queue.label, "io.sentry.session-replay.asset-worker") - XCTAssertEqual(assetWorkerQueue.queue.qos.qosClass, .background) + XCTAssertEqual(assetWorkerQueue.queue.qos.qosClass, .utility) XCTAssertEqual(processingQueue.queue.label, "io.sentry.session-replay.processing") - XCTAssertEqual(processingQueue.queue.qos.qosClass, .background) + XCTAssertEqual(processingQueue.queue.qos.qosClass, .utility) // The actual priorities are not relevant, we just need to check that the processing queue has a lower priority // than the asset worker queue and that both are lower than the default priority. diff --git a/Tests/SentryTests/Networking/SentryDispatchFactoryTests.m b/Tests/SentryTests/Networking/SentryDispatchFactoryTests.m index 9f791910c1e..f2ee9f5243b 100644 --- a/Tests/SentryTests/Networking/SentryDispatchFactoryTests.m +++ b/Tests/SentryTests/Networking/SentryDispatchFactoryTests.m @@ -43,7 +43,7 @@ - (void)testQueueWithNameAndAttributes_shouldReturnQueueWithNameAndAttributesSet } - (void) - testCreateBackgroundQueueWithNameAndRelativePriority_shouldReturnQueueWithNameAndRelativePrioritySet + testCreateLowPriorityQueueWithNameAndRelativePriority_shouldReturnQueueWithNameAndRelativePrioritySet { // Note: We are not testing the functionality of the queue itself, just the creation of it, // making sure the factory sets the name and attributes correctly. @@ -53,8 +53,8 @@ - (void)testQueueWithNameAndAttributes_shouldReturnQueueWithNameAndAttributesSet int relativePriority = -5; // -- Act -- - SentryDispatchQueueWrapper *wrappedQueue = - [self.sut createBackgroundQueueWithName:queueName relativePriority:relativePriority]; + SentryDispatchQueueWrapper *wrappedQueue = [self.sut createLowPriorityQueue:queueName + relativePriority:relativePriority]; // -- Assert -- const char *actualName = dispatch_queue_get_label(wrappedQueue.queue); @@ -63,7 +63,7 @@ - (void)testQueueWithNameAndAttributes_shouldReturnQueueWithNameAndAttributesSet int actualRelativePriority; dispatch_qos_class_t actualQoSClass = dispatch_queue_get_qos_class(wrappedQueue.queue, &actualRelativePriority); - XCTAssertEqual(actualQoSClass, QOS_CLASS_BACKGROUND); + XCTAssertEqual(actualQoSClass, QOS_CLASS_UTILITY); XCTAssertEqual(actualRelativePriority, relativePriority); } @@ -111,7 +111,7 @@ - (void)testSource_queueUsesCorrectQoSAndPriority uint64_t leeway = 0; const char *queueName = "sentry-dispatch-factory.qos-check"; dispatch_queue_attr_t attributes - = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_BACKGROUND, -10); + = dispatch_queue_attr_make_with_qos_class(DISPATCH_QUEUE_SERIAL, QOS_CLASS_UTILITY, -10); void (^eventHandler)(void) = ^{ }; // -- Act -- @@ -128,7 +128,7 @@ - (void)testSource_queueUsesCorrectQoSAndPriority int relativePriority; dispatch_qos_class_t qos = dispatch_queue_get_qos_class(queueWrapper.queue, &relativePriority); - XCTAssertEqual(qos, QOS_CLASS_BACKGROUND); + XCTAssertEqual(qos, QOS_CLASS_UTILITY); XCTAssertEqual(relativePriority, -10); } diff --git a/Tests/SentryTests/Networking/SentryDispatchQueueWrapperTests.m b/Tests/SentryTests/Networking/SentryDispatchQueueWrapperTests.m index 085986040a9..6eabbf97c3f 100644 --- a/Tests/SentryTests/Networking/SentryDispatchQueueWrapperTests.m +++ b/Tests/SentryTests/Networking/SentryDispatchQueueWrapperTests.m @@ -29,7 +29,7 @@ - (void)testInitWithNameAndAttributes_customAttributes_shouldCreateQueueWithGive // -- Arrange -- const char *queueName = "sentry-dispatch-factory.test"; int relativePriority = -5; - qos_class_t qosClass = QOS_CLASS_BACKGROUND; + qos_class_t qosClass = QOS_CLASS_UTILITY; dispatch_queue_attr_t _Nullable attr = DISPATCH_QUEUE_SERIAL; dispatch_queue_attr_t _Nullable attributes @@ -43,7 +43,7 @@ - (void)testInitWithNameAndAttributes_customAttributes_shouldCreateQueueWithGive int actualRelativePriority; dispatch_qos_class_t actualQoSClass = dispatch_queue_get_qos_class(wrappedQueue.queue, &actualRelativePriority); - XCTAssertEqual(actualQoSClass, QOS_CLASS_BACKGROUND); + XCTAssertEqual(actualQoSClass, QOS_CLASS_UTILITY); XCTAssertEqual(actualRelativePriority, -5); } @@ -58,7 +58,7 @@ - (void)testInitWithNameAndAttributes_customAttributes_shouldCreateQueueWithGive // -- Arrange -- const char *queueName = "sentry-dispatch-factory.test"; int relativePriority = 5; - qos_class_t qosClass = QOS_CLASS_BACKGROUND; + qos_class_t qosClass = QOS_CLASS_UTILITY; dispatch_queue_attr_t _Nullable attr = DISPATCH_QUEUE_SERIAL; dispatch_queue_attr_t _Nullable attributes