Recipes
Keep only the latest search
Debounce rapid input and restart obsolete processing within one explicit execution group.
Keep only the latest search
A search box creates two different kinds of obsolete work. Commands may still be waiting for a quiet input window, or an earlier request may already be processing. Debounce controls the first case; restart controls the second.
Give related searches a key
final class SearchCatalog extends UseCaseCommand {
const SearchCatalog({required this.catalog, required this.query});
final String catalog;
final String query;
@override
Object get executionKey => catalog;
}
The key makes searches for the same catalog related. A search in another catalog remains independent. Exact command type is also part of the group identity.
Combine admission and processing policies
registerCommand<SearchCatalog>(
_search,
instructions: UseCaseInstructionOverrides(
input: UseCaseInputInstructionOverrides(
debounce: UseCaseDebounceInstructions(
duration: const Duration(milliseconds: 300),
),
),
processing: const UseCaseProcessingInstructionOverrides(
existingExecutionPolicy: UseCaseExistingExecutionPolicy.restart,
),
),
);
Trailing debounce retains the last candidate during rapid input. When that candidate reaches processing, restart requests infrastructure cancellation for an active related execution before starting the new one.
What to observe
- displaced debounce candidates reach
onCommandRejectedwith a typed reason; - a restarted active execution terminates as cancelled and is recorded in history;
- the latest execution publishes the visible result;
- unrelated keys continue independently.
Do not add a second UI timer around this policy. The UseCase clock owns the admission window, which also lets tests advance it deterministically.