aptabase / aptabase-swift

Swift SDK for Aptabase: Open Source, Privacy-First and Simple Analytics for Mobile, Desktop and Web Apps
https://aptabase.com
MIT License
21 stars 8 forks source link

Flush sync causes app to hang #18

Closed Claeysson closed 3 months ago

Claeysson commented 6 months ago

Performance issue

Sentry.io reports app hanging for over 2000ms when flushSync() is triggered.

Screenshot 2024-02-29 at 10 43 43

This code in aptabseClient.swift seems to be called on the main thread, and semaphore.wait() locks the main thread.

@objc private func flushSync() {
    let semaphore = DispatchSemaphore(value: 0)
    Task {
        await self.flush()
        semaphore.signal()
    }
    semaphore.wait()
}

Potential fix

I'm not quite sure why semaphore.wait() is used here. My best guess is that I will prevent a new flushSync if the latest hasn't finished executing. I've added a timer pause variable to mimic the wait but with out locking the main thread.

goenning commented 6 months ago

it was build this way to ensure the events would be sent when the app goes to background, that’s the only scenario where flushSync is called, but honestly I don’t know if it’s actually necessary. I suppose the OS would give the app to finish any IO tasks

dalenjohnson commented 4 months ago

I am seeing app crashes from what I believe is this same issue. The app will hang on launch and will crash after about 30 seconds. I am only seeing this hang and crash when the app has no network connection.

I do NOT see the hang and crash when running in the simulator only on real devices. I do NOT see the issue when launching the app with airplane mode on. I DO see the issue if the device has an active wifi/cellular connection but all traffic is blocked in the Network Link Conditioner simulating a bad connection.

Devices: iPhone 14 Pro & iPad mini 6th gen OS: iOS 17.4.1 Aptabase: 0.3.8

I am seeing the following in the crash logs from the real device. This is what make me think this is the same issue, it references semaphore_wait_trap and AptabaseClient.flushSync

Exception Type:  EXC_CRASH (SIGKILL)
Exception Codes: 0x0000000000000000, 0x0000000000000000
Termination Reason: FRONTBOARD 2343432205 
<RBSTerminateContext| domain:10 code:0x8BADF00D explanation:scene-create watchdog transgression: app<>:6431 exhausted real (wall clock) time allowance of 19.94 seconds
ProcessVisibility: Foreground
ProcessState: Running
WatchdogEvent: scene-create
WatchdogVisibility: Foreground
WatchdogCPUStatistics: (
"Elapsed total CPU time (seconds): 20.240 (user 15.610, system 4.630), 16% CPU",
"Elapsed application CPU time (seconds): 0.131, 0% CPU"
) reportType:CrashLog maxTerminationResistance:Interactive>

Triggered by Thread:  0

Thread 0 name:   Dispatch queue: com.apple.main-thread
Thread 0 Crashed:
0   libsystem_kernel.dylib                 0x1ef7bda74 semaphore_wait_trap + 8
1   libdispatch.dylib                      0x1af15f370 _dispatch_sema4_wait + 28
2   libdispatch.dylib                      0x1af15fa20 _dispatch_semaphore_wait_slow + 132
3   TEST APP                               0x102adbc44 AptabaseClient.flushSync() + 272
4   TEST APP                               0x102adb990 AptabaseClient.stopPolling() + 268
5   TEST APP                               0x102adb6c0 AptabaseClient.startPolling() + 40
6   TEST APP                               0x102ad8804 Aptabase.startPolling() + 100
7   TEST APP                               0x102ad8850 @objc Aptabase.startPolling() + 36
8   CoreFoundation                         0x1a72917a8 __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 148
9   CoreFoundation                         0x1a7291170 ___CFXRegistrationPost_block_invoke + 88
10  CoreFoundation                         0x1a72910b8 _CFXRegistrationPost + 440
11  CoreFoundation                         0x1a7290608 _CFXNotificationPost + 728
12  Foundation                             0x1a6122f10 -[NSNotificationCenter postNotificationName:object:userInfo:] + 92
13  UIKitCore                              0x1a966b04c -[UIApplication _sendWillEnterForegroundCallbacks] + 212
14  UIKitCore                              0x1a96697cc __101-[_UISceneLifecycleMultiplexer _evalTransitionToSettings:fromSettings:forceExit:withTransitionStore:]_block_invoke_2 + 1272
15  UIKitCore                              0x1a9669298 _UIScenePerformActionsWithLifecycleActionMask + 112
16  UIKitCore                              0x1a96ef934 __101-[_UISceneLifecycleMultiplexer _evalTransitionToSettings:fromSettings:forceExit:withTransitionStore:]_block_invoke + 216
17  UIKitCore                              0x1a9618ac4 -[_UISceneLifecycleMultiplexer _performBlock:withApplicationOfDeactivationReasons:fromReasons:] + 220
18  UIKitCore                              0x1a961753c -[_UISceneLifecycleMultiplexer _evalTransitionToSettings:fromSettings:forceExit:withTransitionStore:] + 608
19  UIKitCore                              0x1a9616ea4 -[_UISceneLifecycleMultiplexer uiScene:transitionedFromState:withTransitionContext:] + 248
20  UIKitCore                              0x1a9616d74 __186-[_UIWindowSceneFBSSceneTransitionContextDrivenLifecycleSettingsDiffAction _performActionsForUIScene:withUpdatedFBSScene:settingsDiff:fromSettings:transitionContext:lifecycleActionType:]_block_invoke + 148
21  UIKitCore                              0x1a9616c7c +[BSAnimationSettings(UIKit) tryAnimatingWithSettings:fromCurrentState:actions:completion:] + 736
22  UIKitCore                              0x1a9616504 _UISceneSettingsDiffActionPerformChangesWithTransitionContextAndCompletion + 224
23  UIKitCore                              0x1a96161b4 -[_UIWindowSceneFBSSceneTransitionContextDrivenLifecycleSettingsDiffAction _performActionsForUIScene:withUpdatedFBSScene:settingsDiff:fromSettings:transitionContext:lifecycleActionType:] + 316
24  UIKitCore                              0x1a99a6e20 __64-[UIScene scene:didUpdateWithDiff:transitionContext:completion:]_block_invoke.226 + 612
25  UIKitCore                              0x1a9615328 -[UIScene _emitSceneSettingsUpdateResponseForCompletion:afterSceneUpdateWork:] + 216
26  UIKitCore                              0x1a9615198 -[UIScene scene:didUpdateWithDiff:transitionContext:completion:] + 244
27  UIKitCore                              0x1a972bf74 -[UIApplication workspace:didCreateScene:withTransitionContext:completion:] + 508
28  UIKitCore                              0x1a972bd0c -[UIApplicationSceneClientAgent scene:didInitializeWithEvent:completion:] + 288
29  FrontBoardServices                     0x1bfe48644 -[FBSScene _callOutQueue_didCreateWithTransitionContext:completion:] + 324
30  FrontBoardServices                     0x1bfe484e0 __92-[FBSWorkspaceScenesClient createSceneWithIdentity:parameters:transitionContext:completion:]_block_invoke.108 + 280
31  FrontBoardServices                     0x1bfe4710c -[FBSWorkspace _calloutQueue_executeCalloutFromSource:withBlock:] + 168
32  FrontBoardServices                     0x1bfe52bf0 __92-[FBSWorkspaceScenesClient createSceneWithIdentity:parameters:transitionContext:completion:]_block_invoke + 352
33  libdispatch.dylib                      0x1af15edd4 _dispatch_client_callout + 20
34  libdispatch.dylib                      0x1af16286c _dispatch_block_invoke_direct + 288
35  FrontBoardServices                     0x1bfe43490 __FBSSERIALQUEUE_IS_CALLING_OUT_TO_A_BLOCK__ + 52
36  FrontBoardServices                     0x1bfe43410 -[FBSMainRunLoopSerialQueue _targetQueue_performNextIfPossible] + 240
37  FrontBoardServices                     0x1bfe432e8 -[FBSMainRunLoopSerialQueue _performNextFromRunLoopSource] + 28
38  CoreFoundation                         0x1a729962c __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 28
39  CoreFoundation                         0x1a72988a8 __CFRunLoopDoSource0 + 176
40  CoreFoundation                         0x1a72970b8 __CFRunLoopDoSources0 + 340
41  CoreFoundation                         0x1a7295d88 __CFRunLoopRun + 828
42  CoreFoundation                         0x1a7295968 CFRunLoopRunSpecific + 608
43  GraphicsServices                       0x1eb58b4e0 GSEventRunModal + 164
44  UIKitCore                              0x1a9708edc -[UIApplication _run] + 888
45  UIKitCore                              0x1a9708518 UIApplicationMain + 340
46  SwiftUI                                0x1ac0cf860 0x1ab09c000 + 16988256
47  SwiftUI                                0x1ac0cf6a8 0x1ab09c000 + 16987816
48  SwiftUI                                0x1abceb9fc 0x1ab09c000 + 12909052
49  TEST APP                               0x102a02efc static TESTAPPApp.$main() + 40
50  TEST APP                               0x102a02fc8 main + 12
51  dyld                                   0x1ca7b6d84 start + 2240

On the simulator where I do NOT see the crash I get the following errors in the console log repeating forever:

Connection 1: received failure notification
Connection 1: failed to connect 1:50, reason 18,446,744,073,709,551,615
Connection 1: encountered error(1:50)
Task <781E09CC-4933-4A72-BA80-F905341BEDB7>.<1> HTTP load failed, 0/0 bytes (error code: 18,446,744,073,709,550,607 [1:50])
"Aptabase: Failed to send 1 events. Reason: Error Domain=NSURLErrorDomain Code=-1009 \"The Internet connection appears to be offline.\" UserInfo={_kCFStreamErrorCodeKey=50, NSUnderlyingError=0x600000c5f090 {Error Domain=kCFErrorDomainCFNetwork Code=-1009 \"(null)\" UserInfo={_kCFStreamErrorDomainKey=1, _kCFStreamErrorCodeKey=50, _NSURLErrorNWResolutionReportKey=Resolved 0 endpoints in 14ms using unknown from cache, _NSURLErrorNWPathKey=unsatisfied (No network route)}}, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <781E09CC-4933-4A72-BA80-F905341BEDB7>.<1>, _NSURLErrorRelatedURLSessionTaskErrorKey=(\n    \"LocalDataTask <781E09CC-4933-4A72-BA80-F905341BEDB7>.<1>\"\n), NSLocalizedDescription=The Internet connection appears to be offline., NSErrorFailingURLStringKey=https://us.aptabase.com/api/v0/events, NSErrorFailingURLKey=https://us.aptabase.com/api/v0/events, _kCFStreamErrorDomainKey=1}"
Task <781E09CC-4933-4A72-BA80-F905341BEDB7>.<1> finished with error [18,446,744,073,709,550,607] Error Domain=NSURLErrorDomain Code=-1009 "The Internet connection appears to be offline." UserInfo={_kCFStreamErrorCodeKey=50, NSUnderlyingError=0x600000c5f090 {Error Domain=kCFErrorDomainCFNetwork Code=-1009 "(null)" UserInfo={_kCFStreamErrorDomainKey=1, _kCFStreamErrorCodeKey=50, _NSURLErrorNWResolutionReportKey=Resolved 0 endpoints in 14ms using unknown from cache, _NSURLErrorNWPathKey=unsatisfied (No network route)}}, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <781E09CC-4933-4A72-BA80-F905341BEDB7>.<1>, _NSURLErrorRelatedURLSessionTaskErrorKey=(
    "LocalDataTask <781E09CC-4933-4A72-BA80-F905341BEDB7>.<1>"
), NSLocalizedDescription=The Internet connection appears to be offline., NSErrorFailingURLStringKey=https://us.aptabase.com/api/v0/events, NSErrorFailingURLKey=https://us.aptabase.com/api/v0/events, _kCFStreamErrorDomainKey=1}
dalenjohnson commented 4 months ago

I just tested the code changes in PR #19 and it seems to fix the crash I mentioned above. Could that be merged into the main repo soon?

cristipufu commented 3 months ago

Hi @Claeysson @dalenjohnson - the 0.3.9 version is up & running, please let us know if everything works as expected, thanks!