Skip to content

fix(session-replay): Use low priority queue for dispatch queue wrapper #5280

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

Merged
merged 5 commits into from
May 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
9 changes: 6 additions & 3 deletions Sources/Sentry/SentryDispatchFactory.m
Original file line number Diff line number Diff line change
Expand Up @@ -11,13 +11,16 @@
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);

Check warning on line 23 in Sources/Sentry/SentryDispatchFactory.m

View check run for this annotation

Codecov / codecov/patch

Sources/Sentry/SentryDispatchFactory.m#L23

Added line #L23 was not covered by tests
return [[SentryDispatchQueueWrapper alloc] initWithName:name attributes:attributes];
}

Expand Down
8 changes: 4 additions & 4 deletions Sources/Sentry/SentrySessionReplayIntegration.m
Original file line number Diff line number Diff line change
Expand Up @@ -143,14 +143,14 @@
// 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];

Check warning on line 147 in Sources/Sentry/SentrySessionReplayIntegration.m

View check run for this annotation

Codecov / codecov/patch

Sources/Sentry/SentrySessionReplayIntegration.m#L146-L147

Added lines #L146 - L147 were not covered by tests
// 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];

Check warning on line 153 in Sources/Sentry/SentrySessionReplayIntegration.m

View check run for this annotation

Codecov / codecov/patch

Sources/Sentry/SentrySessionReplayIntegration.m#L152-L153

Added lines #L152 - L153 were not covered by tests

// The asset worker queue is used to work on video and frames data.

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
12 changes: 6 additions & 6 deletions Tests/SentryTests/Networking/SentryDispatchFactoryTests.m
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand All @@ -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);
Expand All @@ -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);
}

Expand Down Expand Up @@ -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 --
Expand All @@ -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);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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);
}

Expand All @@ -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
Expand Down
Loading