Repository navigation
feat: [SDK-5396] send a heartbeat every 30 minutes of foreground time - #2782
Merged
Merged
Conversation
Contributor
📊 Diff Coverage ReportDiff Coverage Report (Changed Lines Only)Gate: aggregate coverage on changed executable lines must be ≥ 80% (JaCoCo line data for lines touched in the diff). Changed Files Coverage
Overall (aggregate gate)54/54 touched executable lines covered (100.0% — requires ≥ 80%) |
9 of 18 tasks
abdulraqeeb33
approved these changes
Oct 12, 2026
abdulraqeeb33
left a comment
Contributor
There was a problem hiding this comment.
Approving.
Foreground time only, remaining time recomputed after wake, and a kill while focused ends at max(activeDuration, lastHeartbeatDuration). This depends on #2780 and #2781 holding creates and ends that are missing ids. Those two still drop them.
One nit: lastHeartbeatDuration is written before the enqueue. If the ids are missing, the tick is skipped and the next try waits another 30 minutes. A later successful tick still sends the cumulative duration, so this delays the update rather than losing it.
Base automatically changed from
fadi/SDK-5390-android-session-end
to
new-session-events
October 27, 2026 21:44
While a sessions API session is focused, enqueue a duration-only UpdateSessionOperation every 30 minutes of active time. The timer stops on unfocus and resumes on focus, so background time doesn't count. Flag off starts no timer. The last heartbeat's duration and time are persisted on the session, so an end after a kill while focused never reports less than the server already has. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
fadi-george
force-pushed
the
fadi/SDK-5396-android-heartbeat
branch
from
October 27, 2026 22:47
78fcade to
220c3a0
Compare
9 of 18 tasks
A wall-clock jump saved on a heartbeat could move the session end past a later unfocus. Clear the heartbeat time on unfocus so it only counts for a session killed in the foreground. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…nd by a heartbeat's backoff - Catch failures in the heartbeat loop, since the serial IO scope has no exception handler; the heartbeat stops until the next focus. - An end that replaces a backed-off heartbeat keeps its retry count but not its backoff, so it can still send while the background job waits. - Share the focus-duration math between the heartbeat and unfocus, and clarify that lastHeartbeatDuration is set even when nothing was sent. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A wall-clock jump mid-focus could otherwise move a killed session's end past its foreground time. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
One Line Summary
When the sessions API flag is on, send a duration-only session
PATCHevery 30 minutes of foreground time.Details
Motivation
Part of the SDK Sessions stack (SDK-5396). Keeps long foreground sessions alive on the server's inactivity timer and bounds duration loss if the app crashes while foregrounded.
Scope
SessionServicestarts a heartbeat coroutine on focus for sessions whoseusesSessionsApiis true, and cancels it on unfocus.elapsedRealtime) is 30 minutes past the last heartbeat. Background time doesn't count, and each tick's duration is always higher than the last, so unchanged durations are never sent.UpdateSessionOperationwith the cumulative duration and noend_time.SessionQueuePolicyalready folds unsent updates into the newest one and drops updates once the session is closed, so no queue changes.Heartbeatclass to keepSessionServiceunder detekt's function limit.SessionModel. An app killed while focused never adds its last focus toactiveDuration, so the end on the next cold start uses the larger ofactiveDurationand the last heartbeat's duration, and the latest of the unfocus, focus, and heartbeat times asend_time. Otherwise the end could report less than the server already has.SessionQueuePolicy: an end that replaces a backed-off heartbeat keeps its retry count but not itsretryAt, so the background job's 30 s wait isn't spent on a heartbeat's backoff.updateSessionOperation(session, appId, activeDuration, endTime?)and shared with the heartbeat.Testing
Unit testing
Added
SessionServiceTestscases on a virtual clock: one heartbeat after 30 minutes, two after 60, background pauses the timer and only foreground time counts, new session restarts the interval, no timer on the legacy path, no heartbeat (and no busy loop) without a push subscription ID, cold start after a kill following a heartbeat ends with the heartbeat's duration and time, and a session end clears the last heartbeat. Heartbeat fields added to the persistence test.spotlessCheck,detekt, andtestDebugUnitTest(core) pass locally.Manual testing
Not tested on device yet; end-to-end verification is planned in the Android Rollout & QA ticket (SDK-5405).
Affected code checklist
Checklist
Overview
Testing
Final pass
🤖 Generated with Claude Code