States¶
The State mechanism in QTasks allows you to securely store and transfer data between
tasks.
It is implemented in the built-in worker plugin (A)StatePlugin and provides
a convenient interface for working with state.
Example of using State¶
from qtasks.plugins.states import AsyncState
class MyState(AsyncState):
pass
@app.task
async def step1(state: MyState):
await state.set("state", "await_phone")
await state.update(step=1, prompt="Enter phone number")
return "ok"
@app.task
async def step2(state: MyState):
print(await state.get_all())
cur = await state.get("state")
if cur != "await_phone":
return "error"
await state.update(step=2)
await state.delete("state")
await state.clear()
return "ok"
Output of print(await state.get_all()):
{'state': 'await_phone', 'step': 1, 'prompt': 'Enter phone number'}
Scenario:
step1initializes the state and writes several values.step2reads the state, checks it, updates it, and clears it.
This way, multiple tasks can work with a shared thread-safe state.
How it works "under the hood"¶
Below is a simplified description of the internal logic of (A)StatePlugin.
1. Searching for State in task parameters¶
The plugin analyzes the task signature and checks whether the parameter type is
a subclass of AsyncState or State:
issubclass(MyState, (AsyncState, State))
If such a parameter is found, the task is considered to use state.
2. Initializing State and StateRegistry¶
If __init__ has not yet been called for MyState, the plugin:
- creates an instance of the state class (
MyState()), - links it to the internal registry
(A)syncStateRegistry.
The registry is responsible for storing values "inside" and uses locks:
asyncio.Lock()— for asynchronous tasks,threading.Lock()— for synchronous tasks.
This ensures that parallel tasks cannot simultaneously modify the same data in an inconsistent manner.
3. Parameter substitution in a task¶
After initialization, the plugin replaces the task function parameter with the
ready-made MyState object.
Inside the task body, the developer already works with a full-fledged state API.
State / AsyncState API¶
The main state methods are listed below.
get¶
value = await state.get("key", default=None)
key— state key (ifNone, all values are returned).default— default value if the key is not found.
get_all¶
data = await state.get_all()
Returns a dictionary of all state values.
set¶
await state.set("key", value)
Sets the state value by key.
update¶
data = await state.update(step=1, prompt="Enter phone number")
Updates multiple values at once and returns the updated dictionary.
delete¶
await state.delete("key")
Deletes the value by key.
clear¶
await state.clear()
Clears all state values.
Purpose of the State mechanism¶
The State mechanism solves the problem of
thread-safe data transfer between tasks:
- shared memory for related tasks (script steps, chains, dialogs);
- protection against races during parallel access to the state;
- a unified interface for reading, writing, and clearing data.
This is a convenient tool for building complex step-by-step processes and scenarios that require context preservation between tasks.