braze-inc / braze-swift-sdk

https://www.braze.com
Other
48 stars 19 forks source link

[Bug]: Session update observers fire unexpectedly #130

Closed Surferdude667 closed 1 month ago

Surferdude667 commented 1 month ago

Platform

iOS

Platform Version

17.5.1

Braze SDK Version

9.3.0

Xcode Version

15.4

Computer Processor

Apple (M1)

Repro Rate

100% of the time

Steps To Reproduce

Add these three variables to your AppDelegate:

static var braze: Braze? = nil

private var sessionUpdateCancellable: Braze.Cancellable?
private var sessionUpdateTask: Task<Void, Never>?

In UIApplicationDelegate.application(_:didFinishLaunchingWithOptions:) add:

let configuration = Braze.Configuration(
    apiKey: "YOUR-APP-IDENTIFIER-API-KEY",
    endpoint: "YOUR-BRAZE-ENDPOINT"
)
configuration.sessionTimeout = 10
let braze = Braze(configuration: configuration)
AppDelegate.braze = braze

sessionUpdateCancellable = AppDelegate.braze?.subscribeToSessionUpdates { event in
    switch event {
        case .started(let id):
            print("Session \(id) has started")
        case .ended(let id):
            print("Session \(id) has ended")
    }
}

sessionUpdateTask = Task {
    for await event in braze.sessionUpdatesStream {
        switch event {
            case .started(let id):
                print("Session \(id) has started")
            case .ended(let id):
                print("Session \(id) has ended")
        }
    }
}

Expected Behavior

When the app enters the background, I expect a callback with "session ended" after 10 seconds.

Actual Incorrect Behavior

The callback never arrives. However, when I bring the app to the foreground after 10 seconds, I get "session ended" and "session started" right after each other.

The behavior is the same no matter if using the Braze.Cancellable or the sessionUpdatesStream

Verbose Logs

No response

Additional Information

No response

jacksonemiller commented 1 month ago

Hi there, thank you for reporting this.

I think from our perspective, this is actually expected behavior. I see though that our docs suggest different behavior though, so I'll go ahead and fix that.

In this scenario, the Braze session is only expected to log a session end ("se") event when the app is foregrounded again. For analytics purposes, the recorded duration of the session will only track until the app is backgrounded, but we do not end the current session and start a new one until the app is foregrounded again. This way, there is always some Braze session active.

Thanks again for posting this. I am going to close this out for now, but feel free to re-open it or reply if you have any other questions.

Surferdude667 commented 1 month ago

@jacksonemiller Thank you for the quick reply.

When you say "the recorded duration of the session will only track until the app is backgrounded" does that mean it will stop tracking after the specified timeout on configuration.sessionTimeout? And if not, what is the point of setting that timeout?

It also appears to work differently with the Android SDK, where you instead actually get the callback after the specified sessionTimeout when the app is backgrounded.

jerielng commented 1 month ago

Setting the configuration.sessionTimeout value will define the threshold for how long a session will last until you re-foreground. For example, if my session timeout is set to 20 seconds and I background my app for 5 seconds and return it, that will not trigger a session start, whereas returning to my app after 30 seconds will trigger a new session start.

Note that in our Android docs, we do call out that a session event may not necessarily be flushed to the server until the app is re-foregrounded, depending on system resources. Currently, there are some semantic differences between Android and iOS due to platform differences in background work, so this may be a feature request. So we can understand your use case a little better, what are you trying to accomplish/determine based on the session end/start events?