When to use task debouncing
Use task debouncing when you have background tasks that:- Might be triggered multiple times for the same logical operation
- Have some tolerance for delayed execution
- Would benefit from reduced database load and resource usage
- Updating customer metrics after multiple usage events
- Processing webhook events that might arrive in quick succession
- Any operation where you want to “batch” multiple triggers into a single execution
How to use task debouncing
To add debouncing to a Dramatiq task, you need to:- Define a debounce key function: This function generates a unique key that identifies the logical operation being debounced. It takes the same arguments as your task and returns a string key.
- Configure the actor with debounce options: Set the debounce key function and thresholds.
Example implementation
Configuration options
debounce_key: A function that takes the same arguments as your task and returns a string keydebounce_min_threshold: Minimum delay (in seconds) before the task can execute. Defaults toWORKER_DEFAULT_DEBOUNCE_MIN_THRESHOLDif not set.debounce_max_threshold: Maximum delay (in seconds) before the task must execute. Defaults toWORKER_DEFAULT_DEBOUNCE_MAX_THRESHOLDif not set.
Optional debouncing
If you want to make debouncing optional based on runtime conditions, you can set the debounce key function to returnNone when you don’t want to debounce. For example:
How it works
Architecture overview
The task debouncer consists of several components:- Debounce key storage: Uses Redis to store debounce state with a 1-hour TTL
- Middleware:
DebounceMiddlewarethat intercepts task processing - Enqueue logic:
set_debounce_key()function that sets up debounce state when tasks are enqueued - Metrics: Tracks debounced tasks and execution delays
Debounce key structure
Debounce keys are stored in Redis as hash objects with this structure:Execution flow
-
Task enqueue: When a debounced task is enqueued:
- The
set_debounce_key()function creates/updates a Redis hash - The first enqueue sets the
enqueue_timestamp - Subsequent enqueues update the
message_idbut preserve the original timestamp. They take the “ownership” of the task. - A minimum delay is applied to the task
- The
-
Task processing: When a worker picks up a debounced task:
DebounceMiddleware.before_process_message()checks the debounce state- If the key was already executed, the task is skipped
- If the current message owns the key (message_id matches), it executes
- If another message owns the key, it checks if max threshold is reached
- If max threshold is reached, the current task executes and becomes the new owner
-
Post-execution: After successful execution:
- The
executedflag is set to prevent further executions from tasks in the same debounce window - Metrics are recorded for monitoring
- The
Debounce scenarios
The following scenarios illustrate how the debouncer behaves in common situations. In all examples,min_threshold is 10s and max_threshold is 60s.
Scenario 1: Single enqueue — basic execution
The simplest case: one task is enqueued, delayed bymin_threshold, and executed.
Scenario 2: Multiple enqueues coalesce into one execution
Three tasks are enqueued for the same debounce key in quick succession. Only the last one (the owner) executes; the others are skipped.Scenario 3: Max threshold prevents starvation
When tasks are continuously enqueued, ownership keeps shifting and the owner never gets a chance to run. The max threshold guarantees execution after a bounded delay.Scenario 4: Re-enqueue after execution starts a new window
Once a task has executed and markedexecuted: 1, a new enqueue resets the debounce state and starts a fresh window.
Monitoring and metrics
The debouncer emits two key metrics:polar_task_debounced_total: Counter of tasks that were skipped due to debouncingpolar_task_debounce_delay_seconds: Histogram of delays between first enqueue and execution
queue and task_name for filtering.
