A background task is a special type of EventHandler that may run
concurrently with other EventHandler functions. This enables long-running
tasks to execute without blocking UI interactivity.
A background task is defined by decorating an async State method with
@rx.event(background=True).
@rx.event(background=True) used to be called @rx.background.
Whenever a background task needs to interact with the state, it must enter an
async with self context block which refreshes the state and takes an
exclusive lock to prevent other tasks or event handlers from modifying it
concurrently. Because other EventHandler functions may modify state while the
task is running, outside of the context block, Vars accessed by the background
task may be stale. Attempting to modify the state from a background task
outside of the context block will raise an ImmutableStateError exception.
In the following example, the my_task event handler is decorated with
@rx.event(background=True) and increments the counter variable every half second, as
long as certain conditions are met. While it is running, the UI remains
interactive and continues to process events normally.
Background events are similar to simple Task Queues like Celery allowing asynchronous events.
Sometimes, background tasks may continue running even after the user navigates away from the page or closes the browser tab. To handle such cases, you can check if the websocket associated with the state is disconnected and terminate the background task when necessary.
The solution involves checking if the client_token is still valid in the app.event_namespace.token_to_sid mapping. If the session is lost (e.g., the user navigates away or closes the page), the background task will stop.
When a background task is triggered, it starts immediately, saving a reference to
the task in app.background_tasks. When the task completes, it is removed from
the set.
Multiple instances of the same background task may run concurrently, and the
framework makes no attempt to avoid duplicate tasks from starting.
It is up to the developer to ensure that duplicate tasks are not created under
the circumstances that are undesirable. In the example above, the _n_tasks
backend var is used to control whether my_task will enter the increment loop,
or exit early.