The uniqueness of QTasks¶
QTasks is not just an alternative to Celery or RQ. It is a framework with a different approach to task queue architecture: flexible, modular, and expansion-oriented. Below are the key features that set it apart.
🧬 Component-based architecture¶
- All key elements (Broker, Worker, Storage, GlobalConfig, Starter, TaskExecutor, etc.) are fully replaceable.
- Components can be rewritten for your own infrastructure without changing the core.
- Extensions are connected via plugins and starters.
🆚 Celery: monolithic bundle. QTasks: independent components with a plug-and-play approach.
🔁 Support for yield in tasks¶
Allows you to build step-by-step, streamlined scenarios.
- Support for generators in tasks.
- Processing of
yieldresults viagenerate_handler. - The final
returnvalue is returned as a normal task result.
@app.task(generate_handler=handler)
def task():
step = yield "INIT"
return step
🆚 Most frameworks do not support generator-based tasks.
🧠 Echo and access to the task via self¶
When echo=True is enabled, the task becomes a Task (Async/Sync) object, which
opens access to the infrastructure:
self.add_task()— creating nested tasksself.ctx.get_logger()— contextual loggerself.ctx.cancel()— terminating a task earlyself.ctx.get_task()— getting another task by UUID
🆚 In other frameworks, a task is a simple function without a self context.
⚙️ Execution context (ctx)¶
The task context provides:
- Task UUID
- Access to Broker, Storage, GlobalConfig
- metadata manipulation (
get_metadata()) - safe sleep (
ctx.sleep()) - task cancellation (
cancel())
This allows you to build complex scenarios without global variables and third-party singletons.
🔗 State and Depends¶
State¶
Thread-safe storage of intermediate data between tasks.
from qtasks.plugins import AsyncState
class MyState(AsyncState):
pass
@app.task
def sample(state: MyState):
...
Depends¶
Injecting dependencies into tasks:
@app.task
def job(data: int, db=Depends(connect_db, scope="worker")):
return db.save(data)
Scopes include:
- task
- worker
- broker
- storage
- global_config
QTasks automatically creates and completes dependencies for the specified scope.
🧩 Plugins and starters¶
- Plugins can be attached to any events (triggers) within the system.
- You can extend the behavior of Worker, Broker, Storage, and TaskExecutor.
- Starters manage the lifecycle of components and allow you to implement custom flow scenarios.
🆚 Celery requires monkeypatching or deep modification.
⏱ Timers without a separate service¶
The built-in AsyncTimer runs tasks on a schedule:
- cron logic via
apscheduler - integration with the application without a separate process such as Celery Beat
🛠 Minimal dependencies, easy to start¶
- Can work without Redis and brokers — via in-memory queue.
- Launch:
python main.py
qtasks -A app:app run
- Simplicity allows QTasks to be used in microservices, automation, and freelance projects.
🚀 Performance¶
- 0.6–0.7 seconds per task with Redis.
- Asynchronous processing via
PriorityQueueandanyio.Semaphore. - Low overhead even for large volumes of tasks.
🧪 Testing infrastructure¶
SyncTestCaseandAsyncTestCasereplace components for isolated testing.- Works without running a worker.
- Supports
pytest,unittest,pytest-asyncio.
💡 Suitable for any level of developer¶
- Junior: simplicity of API
- Middle: plugins, middleware, TaskManager
- Senior: component replacement, context management, custom executors
- Lead: monitoring, scaling, system architecture on QTasks
QTasks is a constructor that allows you to assemble a framework for your tasks: from a small script to a distributed service.