Skip to content

Commit 38b36f5

Browse files
impr: Capture transactions on a bg thread (#3892)
Instead of capturing and serializing the transaction on the calling thread, the SDK now does this on a background thread. Fixes GH-3826
1 parent c8dbe73 commit 38b36f5

File tree

14 files changed

+58
-34
lines changed

14 files changed

+58
-34
lines changed

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,10 @@
66

77
- Don't transmit device boot time in envelopes enriched with crash data (#3912)
88

9+
### Improvements
10+
11+
- Capture transactions on a background thread (#3892)
12+
913
## 8.25.0-alpha.0
1014

1115
### Features

Samples/iOS-Swift/iOS-Swift/ViewControllers/TraceTestViewController.swift

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -68,15 +68,11 @@ class TraceTestViewController: UIViewController {
6868
return
6969
}
7070

71-
guard let child = children.first(where: { $0.operation == "http.client" }) else {
72-
UIAssert.fail("Did not found http request child")
71+
guard let child = children.first(where: { $0.operation == "http.client" && $0.data["url"] as? String == "https://sentry-brand.storage.googleapis.com/sentry-logo-black.png" && $0.data["http.response.status_code"] as? String == "200" }) else {
72+
UIAssert.fail("Did not find child span for HTTP for retrieving the sentry brand logo.")
7373
return
7474
}
7575

76-
UIAssert.isEqual(child.data["url"] as? String, "https://sentry-brand.storage.googleapis.com/sentry-logo-black.png", "Could not read url data value")
77-
78-
UIAssert.isEqual(child.data["http.response.status_code"] as? String, "200", "Could not read status_code tag value")
79-
8076
UIAssert.checkForViewControllerLifeCycle(span, viewController: "TraceTestViewController", stepsToCheck: self.lifeCycleSteps)
8177
}
8278
}

Sources/Sentry/SentryHub.m

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040

4141
@property (nullable, nonatomic, strong) SentryClient *client;
4242
@property (nullable, nonatomic, strong) SentryScope *scope;
43+
@property (nonatomic) SentryDispatchQueueWrapper *dispatchQueue;
4344
@property (nonatomic, strong) SentryCrashWrapper *crashWrapper;
4445
@property (nonatomic, strong) NSMutableSet<NSString *> *installedIntegrationNames;
4546
@property (nonatomic) NSUInteger errorsBeforeSession;
@@ -57,14 +58,15 @@ - (instancetype)initWithClient:(nullable SentryClient *)client
5758
if (self = [super init]) {
5859
_client = client;
5960
_scope = scope;
61+
_dispatchQueue = SentryDependencyContainer.sharedInstance.dispatchQueueWrapper;
6062
SentryStatsdClient *statsdClient = [[SentryStatsdClient alloc] initWithClient:client];
6163
SentryMetricsClient *metricsClient =
6264
[[SentryMetricsClient alloc] initWithClient:statsdClient];
6365
_metrics = [[SentryMetricsAPI alloc]
6466
initWithEnabled:client.options.enableMetrics
6567
client:metricsClient
6668
currentDate:SentryDependencyContainer.sharedInstance.dateProvider
67-
dispatchQueue:SentryDependencyContainer.sharedInstance.dispatchQueueWrapper
69+
dispatchQueue:_dispatchQueue
6870
random:SentryDependencyContainer.sharedInstance.random
6971
beforeEmitMetric:client.options.beforeEmitMetric];
7072
[_metrics setDelegate:self];
@@ -85,9 +87,11 @@ - (instancetype)initWithClient:(nullable SentryClient *)client
8587
- (instancetype)initWithClient:(nullable SentryClient *)client
8688
andScope:(nullable SentryScope *)scope
8789
andCrashWrapper:(SentryCrashWrapper *)crashWrapper
90+
andDispatchQueue:(SentryDispatchQueueWrapper *)dispatchQueue
8891
{
8992
self = [self initWithClient:client andScope:scope];
9093
_crashWrapper = crashWrapper;
94+
_dispatchQueue = dispatchQueue;
9195

9296
return self;
9397
}
@@ -268,25 +272,31 @@ - (void)captureCrashEvent:(SentryEvent *)event withScope:(SentryScope *)scope
268272
}
269273
}
270274

271-
- (SentryId *)captureTransaction:(SentryTransaction *)transaction withScope:(SentryScope *)scope
275+
- (void)captureTransaction:(SentryTransaction *)transaction withScope:(SentryScope *)scope
272276
{
273-
return [self captureTransaction:transaction withScope:scope additionalEnvelopeItems:@[]];
277+
[self captureTransaction:transaction withScope:scope additionalEnvelopeItems:@[]];
274278
}
275279

276-
- (SentryId *)captureTransaction:(SentryTransaction *)transaction
277-
withScope:(SentryScope *)scope
278-
additionalEnvelopeItems:(NSArray<SentryEnvelopeItem *> *)additionalEnvelopeItems
280+
- (void)captureTransaction:(SentryTransaction *)transaction
281+
withScope:(SentryScope *)scope
282+
additionalEnvelopeItems:(NSArray<SentryEnvelopeItem *> *)additionalEnvelopeItems
279283
{
280284
SentrySampleDecision decision = transaction.trace.sampled;
281285
if (decision != kSentrySampleDecisionYes) {
282286
[self.client recordLostEvent:kSentryDataCategoryTransaction
283287
reason:kSentryDiscardReasonSampleRate];
284-
return SentryId.empty;
288+
return;
285289
}
286290

287-
return [self captureEvent:transaction
288-
withScope:scope
289-
additionalEnvelopeItems:additionalEnvelopeItems];
291+
// When a user calls finish on a transaction, which calls captureTransaction, the calling thread
292+
// here could be the main thread, which we only want to block as long as required. Therefore, we
293+
// capture the transaction on a background thread.
294+
__weak SentryHub *weakSelf = self;
295+
[self.dispatchQueue dispatchAsyncWithBlock:^{
296+
[weakSelf captureEvent:transaction
297+
withScope:scope
298+
additionalEnvelopeItems:additionalEnvelopeItems];
299+
}];
290300
}
291301

292302
- (SentryId *)captureEvent:(SentryEvent *)event

Sources/Sentry/include/SentryHub+Private.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -54,11 +54,11 @@ SentryHub ()
5454
additionalEnvelopeItems:(NSArray<SentryEnvelopeItem *> *)additionalEnvelopeItems
5555
NS_SWIFT_NAME(capture(event:scope:additionalEnvelopeItems:));
5656

57-
- (SentryId *)captureTransaction:(SentryTransaction *)transaction withScope:(SentryScope *)scope;
57+
- (void)captureTransaction:(SentryTransaction *)transaction withScope:(SentryScope *)scope;
5858

59-
- (SentryId *)captureTransaction:(SentryTransaction *)transaction
60-
withScope:(SentryScope *)scope
61-
additionalEnvelopeItems:(NSArray<SentryEnvelopeItem *> *)additionalEnvelopeItems;
59+
- (void)captureTransaction:(SentryTransaction *)transaction
60+
withScope:(SentryScope *)scope
61+
additionalEnvelopeItems:(NSArray<SentryEnvelopeItem *> *)additionalEnvelopeItems;
6262

6363
- (void)captureEnvelope:(SentryEnvelope *)envelope;
6464

Tests/SentryTests/Integrations/Session/SentrySessionGeneratorTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,7 @@ class SentrySessionGeneratorTests: NotificationCenterTestCase {
142142

143143
sentryCrash = TestSentryCrashWrapper.sharedInstance()
144144
let client = SentrySDK.currentHub().getClient()
145-
let hub = SentryHub(client: client, andScope: nil, andCrashWrapper: self.sentryCrash)
145+
let hub = SentryHub(client: client, andScope: nil, andCrashWrapper: self.sentryCrash, andDispatchQueue: SentryDispatchQueueWrapper())
146146
SentrySDK.setCurrentHub(hub)
147147

148148
crashIntegration = SentryCrashIntegration(crashAdapter: sentryCrash, andDispatchQueueWrapper: TestSentryDispatchQueueWrapper())

Tests/SentryTests/Integrations/Session/SentrySessionTrackerTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class SentrySessionTrackerTests: XCTestCase {
3434
}
3535

3636
func setNewHubToSDK() {
37-
let hub = SentryHub(client: client, andScope: nil, andCrashWrapper: self.sentryCrash)
37+
let hub = SentryHub(client: client, andScope: nil, andCrashWrapper: self.sentryCrash, andDispatchQueue: SentryDispatchQueueWrapper())
3838
SentrySDK.setCurrentHub(hub)
3939
}
4040
}

Tests/SentryTests/Integrations/WatchdogTerminations/SentryWatchdogTerminationsIntegrationTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ class SentryWatchdogTerminationIntegrationTests: XCTestCase {
2222
SentryDependencyContainer.sharedInstance().crashWrapper = crashWrapper
2323
SentryDependencyContainer.sharedInstance().fileManager = try! SentryFileManager(options: options, dispatchQueueWrapper: TestSentryDispatchQueueWrapper())
2424

25-
let hub = SentryHub(client: client, andScope: nil, andCrashWrapper: crashWrapper)
25+
let hub = SentryHub(client: client, andScope: nil, andCrashWrapper: crashWrapper, andDispatchQueue: SentryDispatchQueueWrapper())
2626
SentrySDK.setCurrentHub(hub)
2727

2828
fileManager = try! SentryFileManager(options: options, dispatchQueueWrapper: dispatchQueue)

Tests/SentryTests/Integrations/WatchdogTerminations/SentryWatchdogTerminationsTrackerTests.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ class SentryWatchdogTerminationTrackerTests: NotificationCenterTestCase {
2929

3030
crashWrapper = TestSentryCrashWrapper.sharedInstance()
3131

32-
let hub = SentryHub(client: client, andScope: nil, andCrashWrapper: crashWrapper)
32+
let hub = SentryHub(client: client, andScope: nil, andCrashWrapper: crashWrapper, andDispatchQueue: SentryDispatchQueueWrapper())
3333
SentrySDK.setCurrentHub(hub)
3434
}
3535

Tests/SentryTests/SentryHubTests.swift

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ class SentryHubTests: XCTestCase {
2626
let traceOrigin = "auto"
2727
let random = TestRandom(value: 0.5)
2828
let queue = DispatchQueue(label: "SentryHubTests", qos: .utility, attributes: [.concurrent])
29+
let dispatchQueueWrapper = TestSentryDispatchQueueWrapper()
2930

3031
init() {
3132
options = Options()
@@ -52,7 +53,7 @@ class SentryHubTests: XCTestCase {
5253
}
5354

5455
func getSut(_ options: Options, _ scope: Scope? = nil) -> SentryHub {
55-
let hub = SentryHub(client: client, andScope: scope, andCrashWrapper: sentryCrash)
56+
let hub = SentryHub(client: client, andScope: scope, andCrashWrapper: sentryCrash, andDispatchQueue: self.dispatchQueueWrapper)
5657
hub.bindClient(client)
5758
return hub
5859
}
@@ -354,12 +355,23 @@ class SentryHubTests: XCTestCase {
354355
XCTAssertEqual(span.sampled, .no)
355356
}
356357

357-
func testCaptureSampledTransaction_ReturnsEmptyId() {
358+
func testCaptureTransaction_CapturesEventAsync() {
359+
let transaction = sut.startTransaction(transactionContext: TransactionContext(name: fixture.transactionName, operation: fixture.transactionOperation, sampled: .yes))
360+
361+
let trans = Dynamic(transaction).toTransaction().asAnyObject
362+
sut.capture(trans as! Transaction, with: Scope())
363+
364+
expect(self.fixture.client.captureEventWithScopeInvocations.count) == 1
365+
expect(self.fixture.dispatchQueueWrapper.dispatchAsyncInvocations.count) == 1
366+
}
367+
368+
func testCaptureSampledTransaction_DoesNotCaptureEvent() {
358369
let transaction = sut.startTransaction(transactionContext: TransactionContext(name: fixture.transactionName, operation: fixture.transactionOperation, sampled: .no))
359370

360371
let trans = Dynamic(transaction).toTransaction().asAnyObject
361-
let id = sut.capture(trans as! Transaction, with: Scope())
362-
id.assertIsEmpty()
372+
sut.capture(trans as! Transaction, with: Scope())
373+
374+
expect(self.fixture.client.captureEventWithScopeInvocations.count) == 0
363375
}
364376

365377
func testCaptureSampledTransaction_RecordsLostEvent() {

Tests/SentryTests/SentrySDKIntegrationTestsBase.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ class SentrySDKIntegrationTestsBase: XCTestCase {
2626

2727
func givenSdkWithHub(_ options: Options? = nil, scope: Scope = Scope()) {
2828
let client = TestClient(options: options ?? self.options)
29-
let hub = SentryHub(client: client, andScope: scope, andCrashWrapper: TestSentryCrashWrapper.sharedInstance())
29+
let hub = SentryHub(client: client, andScope: scope, andCrashWrapper: TestSentryCrashWrapper.sharedInstance(), andDispatchQueue: SentryDispatchQueueWrapper())
3030

3131
SentrySDK.setCurrentHub(hub)
3232
}

0 commit comments

Comments
 (0)