Skip to content

Storage calls seem to result in main thread deadlocks #277

Closed
@tristan-warner-smith

Description

@tristan-warner-smith

Describe the bug

  • We've updated from the previous SDK Analytics iOS to Analytics Swift and we're experiencing regular app hangs
  • During a hang, pausing execution shows three threads accessing Storage functions that use the blocking syncQueue.sync.
  • We see:
    • Storage.write as a result of a track call where we're making a call to Analytics.track(name:properties:) from the main thread
    • Storage.remove from HttpClient.startBatchUpload > SegmentDestination.flush > Storage.remove
    • Storage.write as a result of another track call, this one from the sync.segment.com serial queue

See attached images.

To Reproduce

  • The behaviour manifests often when switching to other apps and back but often immediately hangs the app on start, leaving it unusable

Our initialisation is:

let analytics = Analytics(
    configuration: Configuration(
        writeKey: Config.shared.segmentSourceKey
    )
    .trackApplicationLifecycleEvents(true)
    .flushAt(3)
    .flushInterval(10)
)
analytics.add(plugin: FirebaseDestination())

let engage = TwilioEngage { _, _ in }
analytics.add(plugin: engage)
analytics.add(plugin: CustomizeSegmentTrackCalls())

Initialisation is lazy on the first track event we fire.

Expected behavior

  • The app should never hang.

Screenshots
Main thread Storage.write

Other Storage calls

Platform (please complete the following information):

  • Library Version in use: 1.4.8
  • Platform being tested: iOS 17
  • Integrations in use: SegmentFirebase, Twilio Engage
  • main commit c4bb71dea0b38c179b2d87b56ee096a06ce2ea86

Additional context

  • The workaround we've had to adopt in the very short-term before you address this bug is to fork the repo and make Storage.write call syncQueue.async rather than syncQueue.sync. This is obviously not ideal, we aren't domain experts in your codebase, but in our testing this change removes all the main-thread blocking issues we encountered and still seems to send Segment events as expected.
  • Both track calls we make are early on in the app's initialisation.
  • We can share a video walking through the stack trace at the point in time of the images above, we'll want to share that privately though.
  • Sometimes it may just be two calls, not three but the end result is the same.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions