Skip to content

Commit ac8d49d

Browse files
robert-smartbearRobert Bartoszewski
andauthored
Fixed an issue where spans weren't sent when BugsnagPerformance has been started on a background thread (#539)
Co-authored-by: Robert Bartoszewski <[email protected]>
1 parent 0d95e1e commit ac8d49d

File tree

9 files changed

+114
-7
lines changed

9 files changed

+114
-7
lines changed

BugsnagPerformance.xcodeproj/project.pbxproj

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,6 +147,8 @@
147147
96F129312DCD325E00A6FB2B /* BugsnagPerformanceSpanTests.mm in Sources */ = {isa = PBXBuildFile; fileRef = 96F129302DCD325E00A6FB2B /* BugsnagPerformanceSpanTests.mm */; };
148148
96F417152E3B8E7000EABD8E /* BugsnagPerformanceNamedSpans.h in Headers */ = {isa = PBXBuildFile; fileRef = 96F417122E3B8E7000EABD8E /* BugsnagPerformanceNamedSpans.h */; };
149149
96F417162E3B8E7000EABD8E /* BugsnagPerformanceNamedSpans.docc in Sources */ = {isa = PBXBuildFile; fileRef = 96F417132E3B8E7000EABD8E /* BugsnagPerformanceNamedSpans.docc */; };
150+
96F9010F2EE817620026F5B9 /* NSTimer+MainThread.h in Headers */ = {isa = PBXBuildFile; fileRef = 96F9010E2EE8175B0026F5B9 /* NSTimer+MainThread.h */; };
151+
96F901112EE817700026F5B9 /* NSTimer+MainThread.m in Sources */ = {isa = PBXBuildFile; fileRef = 96F901102EE817690026F5B9 /* NSTimer+MainThread.m */; };
150152
CB04969729150D860097E526 /* OtlpPackage.h in Headers */ = {isa = PBXBuildFile; fileRef = CB04969529150D860097E526 /* OtlpPackage.h */; };
151153
CB04969829150D860097E526 /* OtlpPackage.mm in Sources */ = {isa = PBXBuildFile; fileRef = CB04969629150D860097E526 /* OtlpPackage.mm */; };
152154
CB04969B2915194E0097E526 /* OtlpUploader.h in Headers */ = {isa = PBXBuildFile; fileRef = CB0496992915194E0097E526 /* OtlpUploader.h */; };
@@ -486,6 +488,8 @@
486488
96F129302DCD325E00A6FB2B /* BugsnagPerformanceSpanTests.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = BugsnagPerformanceSpanTests.mm; sourceTree = "<group>"; };
487489
96F417122E3B8E7000EABD8E /* BugsnagPerformanceNamedSpans.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = BugsnagPerformanceNamedSpans.h; sourceTree = "<group>"; };
488490
96F417132E3B8E7000EABD8E /* BugsnagPerformanceNamedSpans.docc */ = {isa = PBXFileReference; lastKnownFileType = folder.documentationcatalog; path = BugsnagPerformanceNamedSpans.docc; sourceTree = "<group>"; };
491+
96F9010E2EE8175B0026F5B9 /* NSTimer+MainThread.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "NSTimer+MainThread.h"; sourceTree = "<group>"; };
492+
96F901102EE817690026F5B9 /* NSTimer+MainThread.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = "NSTimer+MainThread.m"; sourceTree = "<group>"; };
489493
CB04969529150D860097E526 /* OtlpPackage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OtlpPackage.h; sourceTree = "<group>"; };
490494
CB04969629150D860097E526 /* OtlpPackage.mm */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.objcpp; path = OtlpPackage.mm; sourceTree = "<group>"; };
491495
CB0496992915194E0097E526 /* OtlpUploader.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OtlpUploader.h; sourceTree = "<group>"; };
@@ -721,8 +725,6 @@
721725
0122C21F29019770002D243C /* Private */ = {
722726
isa = PBXGroup;
723727
children = (
724-
1C7852A32E5F697D00BB8E2D /* SpanContext.mm */,
725-
1C7852A12E5F5B2E00BB8E2D /* SpanContext.h */,
726728
CB572EA829BB783200FD7A2A /* AppStateTracker.h */,
727729
CB572EA929BB783200FD7A2A /* AppStateTracker.m */,
728730
CBE8EA1C294B5E1500702950 /* Batch.h */,
@@ -768,6 +770,8 @@
768770
098FC8772D3E8D43001B627D /* Metrics.h */,
769771
09D59E182BDFE0D900199E1B /* NetworkHeaderInjector.h */,
770772
09D59E192BDFE0D900199E1B /* NetworkHeaderInjector.mm */,
773+
96F9010E2EE8175B0026F5B9 /* NSTimer+MainThread.h */,
774+
96F901102EE817690026F5B9 /* NSTimer+MainThread.m */,
771775
CBB48A3A295EE1E10044E9AC /* ObjCUtils.h */,
772776
CBB48A3B295EE1E10044E9AC /* ObjCUtils.mm */,
773777
CB04969529150D860097E526 /* OtlpPackage.h */,
@@ -795,6 +799,8 @@
795799
01A414CC2913C0F0003152A4 /* SpanAttributes.mm */,
796800
96D4160D29F276FE00AEE435 /* SpanAttributesProvider.h */,
797801
96D4160B29F276E400AEE435 /* SpanAttributesProvider.mm */,
802+
1C7852A12E5F5B2E00BB8E2D /* SpanContext.h */,
803+
1C7852A32E5F697D00BB8E2D /* SpanContext.mm */,
798804
963726C42DEAB14D00C739E6 /* SpanControl */,
799805
0122C22329019770002D243C /* SpanKind.h */,
800806
CB7FD935299D330500499E13 /* SpanOptions.h */,
@@ -1179,6 +1185,7 @@
11791185
CBEBE59A29F671A800BF0B4F /* Instrumentation.h in Headers */,
11801186
CBE8EA1E294B5E1500702950 /* Batch.h in Headers */,
11811187
CBEBE59329F2783C00BF0B4F /* Swizzle.h in Headers */,
1188+
96F9010F2EE817620026F5B9 /* NSTimer+MainThread.h in Headers */,
11821189
CBEC51BC296D9EEE009C0CE3 /* PersistentState.h in Headers */,
11831190
0122C23829019770002D243C /* BugsnagPerformanceSpan.h in Headers */,
11841191
966634DA2C8A39B1004A934D /* FrozenFrameData.h in Headers */,
@@ -1632,6 +1639,7 @@
16321639
CBE8EA1B294B5AB800702950 /* Worker.mm in Sources */,
16331640
CB78819C29E587CE00A58906 /* BugsnagPerformanceLibrary.mm in Sources */,
16341641
963726E02DF0B4AD00C739E6 /* BugsnagPerformancePluginContext.m in Sources */,
1642+
96F901112EE817700026F5B9 /* NSTimer+MainThread.m in Sources */,
16351643
098FC8552D37A08D001B627D /* SystemInfoSampler.mm in Sources */,
16361644
963726C82DEAB1FC00C739E6 /* BugsnagPerformancePriority.m in Sources */,
16371645
0122C23C29019770002D243C /* BugsnagPerformanceConfiguration.mm in Sources */,

Sources/BugsnagPerformance/Private/BugsnagPerformanceImpl.mm

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
#import "FrameRateMetrics/FrameMetricsCollector.h"
1919
#import "ConditionTimeoutExecutor.h"
2020
#import "BugsnagPerformanceSpan+Private.h"
21+
#import "NSTimer+MainThread.h"
2122

2223
using namespace bugsnag;
2324

@@ -246,9 +247,9 @@
246247
[worker_ start];
247248
[frameMetricsCollector_ start];
248249

249-
workerTimer_ = [NSTimer scheduledTimerWithTimeInterval:performWorkInterval_
250-
repeats:YES
251-
block:^(__unused NSTimer * _Nonnull timer) {
250+
workerTimer_ = [NSTimer mainThreadTimerWithTimeInterval:performWorkInterval_
251+
repeats:YES
252+
block:^(__unused NSTimer * _Nonnull timer) {
252253
blockThis->onWorkInterval();
253254
}];
254255

Sources/BugsnagPerformance/Private/ConditionTimeoutExecutor.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010

1111
#import <Foundation/Foundation.h>
1212
#import "BugsnagPerformanceSpanCondition+Private.h"
13+
#import "NSTimer+MainThread.h"
1314
#import <map>
1415
#import <mutex>
1516

@@ -21,7 +22,7 @@ class ConditionTimeoutExecutor {
2122

2223
void sheduleTimeout(BugsnagPerformanceSpanCondition *condition, NSTimeInterval timeout) noexcept {
2324
std::lock_guard<std::mutex> guard(mutex_);
24-
this->conditionIdToTimer_[condition.conditionId] = [NSTimer scheduledTimerWithTimeInterval:timeout repeats:NO block:^(NSTimer *) {
25+
this->conditionIdToTimer_[condition.conditionId] = [NSTimer mainThreadTimerWithTimeInterval:timeout repeats:NO block:^(NSTimer *) {
2526
[condition didTimeout];
2627
}];
2728
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
//
2+
// NSTimer+MainThread.h
3+
// BugsnagPerformance
4+
//
5+
// Created by Robert Bartoszewski on 09/12/2025.
6+
// Copyright © 2025 Bugsnag. All rights reserved.
7+
//
8+
9+
#import <Foundation/Foundation.h>
10+
11+
@interface NSTimer (MainThread)
12+
13+
/// Creates and returns a new NSTimer object initialized with the specified block object and schedules it on the main run loop in the default mode.
14+
/// - parameter: ti The number of seconds between firings of the timer. If seconds is less than or equal to 0.0, this method chooses the nonnegative value of 0.1 milliseconds instead
15+
/// - parameter: repeats If YES, the timer will repeatedly reschedule itself until invalidated. If NO, the timer will be invalidated after it fires.
16+
/// - parameter: block The execution body of the timer; the timer itself is passed as the parameter to this block when executed to aid in avoiding cyclical references
17+
+ (NSTimer *)mainThreadTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (NS_SWIFT_SENDABLE ^)(NSTimer *timer))block API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
18+
19+
@end
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
//
2+
// NSTimer+MainThread.m
3+
// BugsnagPerformance
4+
//
5+
// Created by Robert Bartoszewski on 09/12/2025.
6+
// Copyright © 2025 Bugsnag. All rights reserved.
7+
//
8+
9+
#import "NSTimer+MainThread.h"
10+
11+
@implementation NSTimer (MainThread)
12+
13+
+ (NSTimer *)mainThreadTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (NS_SWIFT_SENDABLE ^)(NSTimer *timer))block {
14+
NSTimer *timer = [self timerWithTimeInterval:interval repeats:repeats block:block];
15+
if ([NSThread isMainThread]) {
16+
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
17+
} else {
18+
dispatch_async(dispatch_get_main_queue(), ^{
19+
if ([timer isValid]) {
20+
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
21+
}
22+
});
23+
}
24+
return timer;
25+
}
26+
27+
@end

features/default/manual_spans.feature

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,15 @@ Feature: Manual creation of spans
568568
* the trace payload field "resourceSpans.0.scopeSpans.0.spans.1.parentSpanId" matches the regex "^[A-Fa-f0-9]{16}$"
569569
* the trace payload field "resourceSpans.0.scopeSpans.0.spans.2.parentSpanId" is null
570570

571+
Scenario: Manually start and end spans after starting BugsnagPerformance on a background thread
572+
Given I run "BackgroundThreadStartScenario"
573+
And I wait to receive at least 2 spans
574+
Then the trace "Content-Type" header equals "application/json"
575+
* the trace "Bugsnag-Integrity" header matches the regex "^sha1 [A-Fa-f0-9]{40}$"
576+
* the trace "Bugsnag-Sent-At" header matches the regex "^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d\.\d\d\dZ$"
577+
* a span field "name" equals "BackgroundThreadStartScenarioEarlySpan"
578+
* a span field "name" equals "BackgroundThreadStartScenarioSpan"
579+
571580
Scenario: Parent context should be calculated despite blocked spans on the stack
572581
Given I run "ManualParentBlockedSpanScenario"
573582
And I wait to receive at least 4 spans
@@ -581,4 +590,3 @@ Feature: Manual creation of spans
581590
* a span named "ManualParentBlockedSpanScenarioBlocked1" is a child of span named "ManualParentBlockedSpanScenarioParent"
582591
* a span named "ManualParentBlockedSpanScenarioBlocked2" is a child of span named "ManualParentBlockedSpanScenarioBlocked1"
583592
* a span named "ManualParentBlockedSpanScenarioChild" is a child of span named "ManualParentBlockedSpanScenarioParent"
584-

features/fixtures/ios/Fixture.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@
8181
96DADF512EAFCB1100B56CE6 /* ManualSpanEndOnDestroyScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96DADF502EAFCB1100B56CE6 /* ManualSpanEndOnDestroyScenario.swift */; };
8282
96F129352DCE0CFE00A6FB2B /* ManualSpanWithRemoteContextParentScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96F129342DCE0CFE00A6FB2B /* ManualSpanWithRemoteContextParentScenario.swift */; };
8383
96F5268C2C259E4E0095D600 /* ManualNetworkSpanCallbackSetToNilScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96F5268B2C259E4E0095D600 /* ManualNetworkSpanCallbackSetToNilScenario.swift */; };
84+
96F901132EE81E580026F5B9 /* BackgroundThreadStartScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96F901122EE81E580026F5B9 /* BackgroundThreadStartScenario.swift */; };
8485
96F901172EE836CC0026F5B9 /* ManualParentBlockedSpanScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96F901162EE836CC0026F5B9 /* ManualParentBlockedSpanScenario.swift */; };
8586
96F901092EE7B7FF0026F5B9 /* AutoInstrumentNetworkEarlyCallbackScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96F901082EE7B7FF0026F5B9 /* AutoInstrumentNetworkEarlyCallbackScenario.swift */; };
8687
CB0496942913CA300097E526 /* BatchingWithTimeoutScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB0496932913CA300097E526 /* BatchingWithTimeoutScenario.swift */; };
@@ -188,6 +189,7 @@
188189
96DADF572EAFCE6D00B56CE6 /* BugsnagPerformanceSpan+Internal.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "BugsnagPerformanceSpan+Internal.h"; sourceTree = "<group>"; };
189190
96F129342DCE0CFE00A6FB2B /* ManualSpanWithRemoteContextParentScenario.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManualSpanWithRemoteContextParentScenario.swift; sourceTree = "<group>"; };
190191
96F5268B2C259E4E0095D600 /* ManualNetworkSpanCallbackSetToNilScenario.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManualNetworkSpanCallbackSetToNilScenario.swift; sourceTree = "<group>"; };
192+
96F901122EE81E580026F5B9 /* BackgroundThreadStartScenario.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundThreadStartScenario.swift; sourceTree = "<group>"; };
191193
96F901162EE836CC0026F5B9 /* ManualParentBlockedSpanScenario.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManualParentBlockedSpanScenario.swift; sourceTree = "<group>"; };
192194
96F901082EE7B7FF0026F5B9 /* AutoInstrumentNetworkEarlyCallbackScenario.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoInstrumentNetworkEarlyCallbackScenario.swift; sourceTree = "<group>"; };
193195
CB0496932913CA300097E526 /* BatchingWithTimeoutScenario.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatchingWithTimeoutScenario.swift; sourceTree = "<group>"; };
@@ -321,6 +323,7 @@
321323
9657A8982A3CF75B001CEF5D /* AutoInstrumentTabViewLoadScenario.swift */,
322324
0185C47128F6C983006F9BDC /* AutoInstrumentViewLoadScenario.swift */,
323325
CB572EAC29BB829800FD7A2A /* BackgroundForegroundScenario.swift */,
326+
96F901122EE81E580026F5B9 /* BackgroundThreadStartScenario.swift */,
324327
CBAAE2582912601D006D4AA0 /* BatchingScenario.swift */,
325328
CB0496932913CA300097E526 /* BatchingWithTimeoutScenario.swift */,
326329
09301DC02B63A65A000A7C12 /* ComplexViewScenario.swift */,
@@ -540,6 +543,7 @@
540543
CB572EAD29BB829800FD7A2A /* BackgroundForegroundScenario.swift in Sources */,
541544
966634E02C9DE384004A934D /* FrameMetricsSlowFramesScenario.swift in Sources */,
542545
CB2B8A9F2A0E80B80054FBBE /* AutoInstrumentNetworkBadAddressScenario.swift in Sources */,
546+
96F901132EE81E580026F5B9 /* BackgroundThreadStartScenario.swift in Sources */,
543547
DA58B7D62DF87EC500CB80A4 /* PluginInstallErrorScenario.swift in Sources */,
544548
09F025152BAC50EC007D9F73 /* ViewDidLoadDoesntTriggerScenario.swift in Sources */,
545549
0988B5372CAD32C500D131B1 /* InfraCheckNoBugsnagScenario.swift in Sources */,

features/fixtures/ios/FixtureXcFramework.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,7 @@
8080
96E0B34B2CD0E21C008AEB9C /* AutoInstrumentNetworkSharedSessionInvalidateScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96E0B34A2CD0E21C008AEB9C /* AutoInstrumentNetworkSharedSessionInvalidateScenario.swift */; };
8181
96F129332DCE0CDD00A6FB2B /* RenderingMetricsScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96F129322DCE0CDD00A6FB2B /* RenderingMetricsScenario.swift */; };
8282
96F5268C2C259E4E0095D600 /* ManualNetworkSpanCallbackSetToNilScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96F5268B2C259E4E0095D600 /* ManualNetworkSpanCallbackSetToNilScenario.swift */; };
83+
96F901152EE81E6D0026F5B9 /* BackgroundThreadStartScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96F901142EE81E6D0026F5B9 /* BackgroundThreadStartScenario.swift */; };
8384
96F901192EE836E10026F5B9 /* ManualParentBlockedSpanScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96F901182EE836E10026F5B9 /* ManualParentBlockedSpanScenario.swift */; };
8485
96F9010B2EE7B81F0026F5B9 /* AutoInstrumentNetworkEarlyCallbackScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = 96F9010A2EE7B81F0026F5B9 /* AutoInstrumentNetworkEarlyCallbackScenario.swift */; };
8586
CB0496942913CA300097E526 /* BatchingWithTimeoutScenario.swift in Sources */ = {isa = PBXBuildFile; fileRef = CB0496932913CA300097E526 /* BatchingWithTimeoutScenario.swift */; };
@@ -203,6 +204,7 @@
203204
96E0B34A2CD0E21C008AEB9C /* AutoInstrumentNetworkSharedSessionInvalidateScenario.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AutoInstrumentNetworkSharedSessionInvalidateScenario.swift; sourceTree = "<group>"; };
204205
96F129322DCE0CDD00A6FB2B /* RenderingMetricsScenario.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RenderingMetricsScenario.swift; sourceTree = "<group>"; };
205206
96F5268B2C259E4E0095D600 /* ManualNetworkSpanCallbackSetToNilScenario.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManualNetworkSpanCallbackSetToNilScenario.swift; sourceTree = "<group>"; };
207+
96F901142EE81E6D0026F5B9 /* BackgroundThreadStartScenario.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BackgroundThreadStartScenario.swift; sourceTree = "<group>"; };
206208
96F901182EE836E10026F5B9 /* ManualParentBlockedSpanScenario.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ManualParentBlockedSpanScenario.swift; sourceTree = "<group>"; };
207209
96F9010A2EE7B81F0026F5B9 /* AutoInstrumentNetworkEarlyCallbackScenario.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AutoInstrumentNetworkEarlyCallbackScenario.swift; sourceTree = "<group>"; };
208210
CB0496932913CA300097E526 /* BatchingWithTimeoutScenario.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BatchingWithTimeoutScenario.swift; sourceTree = "<group>"; };
@@ -339,6 +341,7 @@
339341
9657A8982A3CF75B001CEF5D /* AutoInstrumentTabViewLoadScenario.swift */,
340342
0185C47128F6C983006F9BDC /* AutoInstrumentViewLoadScenario.swift */,
341343
CB572EAC29BB829800FD7A2A /* BackgroundForegroundScenario.swift */,
344+
96F901142EE81E6D0026F5B9 /* BackgroundThreadStartScenario.swift */,
342345
CBAAE2582912601D006D4AA0 /* BatchingScenario.swift */,
343346
CB0496932913CA300097E526 /* BatchingWithTimeoutScenario.swift */,
344347
09301DC02B63A65A000A7C12 /* ComplexViewScenario.swift */,
@@ -537,6 +540,7 @@
537540
96F901192EE836E10026F5B9 /* ManualParentBlockedSpanScenario.swift in Sources */,
538541
9691A9E12CA7588700707CDF /* FrameMetricsNonFirstClassSpanInstrumentRenderingOnScenario.swift in Sources */,
539542
09F3F52C2D6C72BD00BAA0A3 /* MemoryMetricsScenario.swift in Sources */,
543+
96F901152EE81E6D0026F5B9 /* BackgroundThreadStartScenario.swift in Sources */,
540544
09637A3F2B06082200F4F776 /* Logging.m in Sources */,
541545
CB3477182901481F0033759C /* AutoInstrumentNetworkWithParentScenario.swift in Sources */,
542546
091B95742CA18F66007DC8A9 /* AutoInstrumentNetworkPreStartDisabledScenario.swift in Sources */,
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
//
2+
// BackgroundThreadStartScenario.swift
3+
// Fixture
4+
//
5+
// Created by Robert Bartoszewski on 09/12/2025.
6+
//
7+
8+
import BugsnagPerformance
9+
10+
@objcMembers
11+
class BackgroundThreadStartScenario: Scenario {
12+
13+
override func setInitialBugsnagConfiguration() {
14+
super.setInitialBugsnagConfiguration()
15+
16+
// Ensure the batch doesn't get full, as we want the spans to be delivered due to reaching work interval
17+
bugsnagPerfConfig.internal.autoTriggerExportOnBatchSize = 100
18+
bugsnagPerfConfig.internal.performWorkInterval = 5.0
19+
}
20+
21+
override func startBugsnag() {
22+
BugsnagPerformance.startSpan(name: "BackgroundThreadStartScenarioEarlySpan").end()
23+
DispatchQueue
24+
.global(qos: .background)
25+
.asyncAfter(deadline: .now() + 2.0) {
26+
super.startBugsnag()
27+
}
28+
}
29+
30+
override func run() {
31+
DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
32+
BugsnagPerformance.startSpan(name: "BackgroundThreadStartScenarioSpan").end()
33+
}
34+
}
35+
}

0 commit comments

Comments
 (0)