Skip to content

Chunk aggregation queries to handle Health Connect's 5000-bucket per-call limit #53

@Kebechet

Description

@Kebechet

Context

Android Health Connect's aggregateGroupByDuration throws when a request would produce more than 5000 buckets:

android.health.connect.HealthConnectException: java.lang.IllegalArgumentException: Number of buckets must not exceed 5000

With a daily interval that caps each call at roughly 13.7 years. The limit isn't in the official docs — it only surfaces at runtime.

Current behavior

After v4.0.0-preview.6, GetAggregatedHealthDataByInterval surfaces this failure correctly via AggregatedIntervalReadResult.ErrorException instead of silently returning an empty list. But the call still fails entirely when the requested window exceeds 5000 buckets — consumers have to clamp their own range or accept the failure.

Proposal

Chunk the aggregation internally when the requested range × interval would exceed the platform limit:

  1. Compute the total bucket count from timeRange and interval.
  2. If ≤ 5000 → single call (current path).
  3. If > 5000 → split the range into sub-windows of ≤ 5000 buckets, call aggregateGroupByDuration once per sub-window, merge the resulting bucket lists in order.

Semantics stay identical from the consumer's perspective — a wide range just costs more IPC round trips.

Scope

  • Android: implement chunking in HealthService.GetAggregatedHealthDataByIntervalInternal (Platforms/Android). The 5000 constant should be named (e.g. HealthConnectMaxBucketsPerCall) and documented as an undocumented platform invariant, surfaced only via the runtime exception.
  • iOS: investigate whether HKStatisticsCollectionQuery has a similar ceiling for very wide ranges. If yes, apply the same chunking; if not, leave the iOS path untouched and note the asymmetry.
  • Tests: unit tests for the chunking math (10000-bucket request → 2 sub-calls; exactly 5000 → 1 call; off-by-one boundary cases; non-daily intervals).

Acceptance

  • GetAggregatedHealthDataByInterval succeeds for arbitrarily wide ranges (subject to cancellation and memory), producing the same bucket set it would if the platform had no limit.
  • AggregatedIntervalReadResult.ErrorException no longer surfaces the 5000-bucket error for windows that differ only in size — only genuine platform errors (permission, SDK unavailable, cancellation, etc.) should propagate.
  • Cancellation across chunks: a cancelled CancellationToken mid-way through chunking aborts further sub-calls cleanly.

Related

  • Follow-up to the error-visibility refactor shipped in v4.0.0-preview.6 that introduced AggregatedIntervalReadResult — without this chunking work, consumers with wide sync windows still hit the failure; the refactor just made it visible instead of silent.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions