Skip to content

Debounce short search queries for longer - #6651

Draft
gpunto wants to merge 3 commits into
developfrom
gianmarcodavid/and-1409-adaptive-search-debounce
Draft

Debounce short search queries for longer#6651
gpunto wants to merge 3 commits into
developfrom
gianmarcodavid/and-1409-adaptive-search-debounce

Conversation

@gpunto

@gpunto gpunto commented Aug 19, 2026

Copy link
Copy Markdown
Contributor

Goal

Message search, the XML search input and the add-members user search send a query as typed, from the first character. Queries of 1-2 characters match a large portion of the data set, so they are the slowest ones to serve and some of them time out, while they are usually just a step towards the query the user is after. Debounce them for at least 500ms instead of the configured 300ms, matching iOS (stream-chat-swift#4198).

Closes AND-1409

Implementation

  • Add SearchDebounce in ui-common, marked @InternalStreamChatApi since the thresholds are not meant to be configured by integrators: 500ms up to 2 characters, the configured debounce from 3 on, and never shorter than the configured one. No public API changes, the API dumps are untouched.
  • Debouncer: internal submit/submitSuspendable overloads taking the debounce period for a single piece of work.
  • Apply it to the Compose message search in ChannelListViewModel, the debounced input listener of SearchInputView, and the user search in AddMembersViewController.
  • SearchInputView.clear() now cancels a debounce still pending from the last keystroke, which notified the listener with the query being cleared and re-ran the search the user had just dismissed.

Channel search is left alone: it only queries from 3 characters on, so it never sends the short autocomplete queryChannels this targets. Mention autocomplete is left alone too, as it queries the members of a single channel.

Testing

  • SearchDebounceTest covers the thresholds, including a configured debounce longer than 500ms winning for short queries.
  • ChannelListViewModelTest: a 2 character message search reaches searchMessages only after 500ms, a 3 character one after 300ms, and a searchDebounceMs above 500ms is honoured for short queries.
  • AddMembersViewControllerTest: a 2 character query starts no search before 500ms. Reverting the controller to the flat 300ms debounce fails this test.
  • DebouncerTest: the new overloads debounce by the period passed per submission, and a later submission cancels pending work.
  • The SearchInputView.clear() fix has no test: ui-components has no Robolectric setup in its unit tests, so there is no harness to drive the view's TextWatcher.

Message search and the add-members user search have no minimum query
length, so a one character query is sent as typed. Those queries match a
large portion of the data set, which makes them the slowest ones to
serve, while they are usually just a step towards the query the user is
after. Debounce queries of 1-2 characters for at least 500ms instead of
the configured 300ms, matching the iOS SDK.

The thresholds live in SearchDebounce in ui-common, marked as internal
API since they are not meant to be configured by integrators: the
existing debounce still applies to regular queries, and wins for short
ones too when it is longer than 500ms.

Applied to the Compose message search in ChannelListViewModel, to the
debounced input listener of the XML SearchInputView, and to the user
search in AddMembersViewController. Channel search is left alone: it
only queries from 3 characters on, so it never sends the short
autocomplete queries this targets, and iOS likewise debounces only
queries built around a text-search operator. Mention autocomplete is
also left alone, as it queries the members of a single channel.

SearchInputView.clear() now cancels a debounce still pending from the
last keystroke, which would otherwise notify the listener with the query
being cleared and re-run the search the user just dismissed.

Debouncer gained internal submit/submitSuspendable overloads taking the
debounce period for a single piece of work. The public API of every
module is unchanged.

AND-1409

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@gpunto gpunto added the pr:improvement Improvement label Aug 19, 2026
@github-actions

Copy link
Copy Markdown
Contributor

PR checklist ✅

All required conditions are satisfied:

  • Title length is OK (or ignored by label).
  • At least one pr: label exists.
  • Sections ### Goal, ### Implementation, and ### Testing are filled, or the PR is bot-authored.
  • An issue is linked (Linear ticket or GitHub issue), or the PR is bot-authored.

🎉 Great job! This PR is ready for review.

@github-actions

Copy link
Copy Markdown
Contributor

SDK Size Comparison 📏

SDK Before After Difference Status
stream-chat-android-client 6.02 MB 6.02 MB 0.00 MB 🟢
stream-chat-android-ui-components 11.32 MB 11.32 MB 0.00 MB 🟢
stream-chat-android-compose 12.80 MB 12.80 MB 0.00 MB 🟢

gpunto and others added 2 commits August 20, 2026 09:37
The add-members search trims the query before building the request, so a
padded short query was debounced as a regular one while firing a one
character queryUsers.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Every touched module already passes -opt-in=InternalStreamChatApi.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@sonarqubecloud

Copy link
Copy Markdown

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

pr:improvement Improvement

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant