Skip to content

Commit b4d5586

Browse files
committed
Add docs and release notes
1 parent 50aa2bc commit b4d5586

5 files changed

Lines changed: 245 additions & 1 deletion

File tree

docs/features/context.md

Lines changed: 154 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,154 @@
1+
# Context Classes
2+
3+
The Context class provides access to task execution metadata and enables efficient resource management through thread-persistent storage. Use it when you need to share resources across multiple task executions in the same worker thread.
4+
5+
## Overview
6+
7+
The `Context` class provides a dual-layer storage system:
8+
9+
- **Worker Layer (`thread_storage`)**: A dictionary that persists across all tasks executed by the same worker thread. Use this for heavy resource pooling (e.g., database engines, HTTP clients) to avoid re-initialization overhead.
10+
- **Task Layer (`metadata`)**: Isolated metadata for each task execution via ContextVars. Provides read-only access to the current task's unique identity and execution state.
11+
12+
## Basic Usage
13+
14+
To use the Context feature, decorate your task function with `@fluxqueue.task_with_context()` instead of `@fluxqueue.task()`. The function must accept a context parameter as its first argument, typed as `Context` or a subclass of `Context`:
15+
16+
```python
17+
from fluxqueue import FluxQueue, Context
18+
19+
fluxqueue = FluxQueue()
20+
21+
@fluxqueue.task_with_context()
22+
def process_data_task(ctx: Context, data: str):
23+
# Access task metadata
24+
print(f"Task ID: {ctx.metadata.task_id}")
25+
print(f"Retry count: {ctx.metadata.retries}")
26+
print(f"Max retries: {ctx.metadata.max_retries}")
27+
print(f"Enqueued at: {ctx.metadata.enqueued_at}")
28+
29+
# Process the data
30+
process_data(data)
31+
```
32+
33+
When you enqueue the task, the context parameter is automatically injected by the worker and is not part of the function's public signature:
34+
35+
```python
36+
# Just call with your regular arguments - no context needed!
37+
process_data_task("some data")
38+
```
39+
40+
## Task Metadata
41+
42+
The `metadata` property provides read-only access to task execution information:
43+
44+
- `task_id`: Unique identifier for the current task execution
45+
- `retries`: Number of times this task has been retried
46+
- `max_retries`: Maximum number of retry attempts allowed
47+
- `enqueued_at`: ISO 8601 timestamp of when the task was originally enqueued
48+
49+
This metadata is isolated per task using Python's `ContextVar`, ensuring data integrity even when multiple tasks execute concurrently on the same thread.
50+
51+
## Custom Context Classes
52+
53+
You can subclass `Context` to create domain-specific contexts that provide convenient access to resources. This is especially useful for database connections, HTTP clients, or other resources that benefit from pooling:
54+
55+
```python
56+
from contextlib import asynccontextmanager
57+
from fluxqueue import FluxQueue, Context
58+
from sqlalchemy.ext.asyncio import create_async_engine, async_sessionmaker, AsyncSession
59+
60+
class DbContext(Context):
61+
"""
62+
Custom context for managing database connections.
63+
64+
This context reuses database engines across tasks in the same worker thread,
65+
significantly reducing connection overhead.
66+
"""
67+
def __init__(self) -> None:
68+
super().__init__()
69+
70+
def _get_local_session(self):
71+
"""
72+
Get or create a session maker for this worker thread.
73+
"""
74+
session = self.thread_storage.get("session")
75+
if session is None:
76+
engine = create_async_engine(DATABASE_URL)
77+
session = async_sessionmaker(
78+
bind=engine, expire_on_commit=False
79+
)
80+
self.thread_storage["session"] = session
81+
return session
82+
83+
@asynccontextmanager
84+
async def session_context(self):
85+
"""
86+
Context manager for database sessions with automatic commit/rollback.
87+
"""
88+
local_session = self._get_local_session()
89+
async with local_session() as session:
90+
try:
91+
yield session
92+
await session.commit()
93+
except Exception:
94+
await session.rollback()
95+
raise
96+
97+
# Use the custom context
98+
@fluxqueue.task_with_context()
99+
async def create_user_task(ctx: DbContext, email: str, username: str):
100+
async with ctx.session_context() as db_session:
101+
user = User(email=email, username=username)
102+
db_session.add(user)
103+
# Session commits automatically on success, rolls back on exception
104+
```
105+
106+
## Benefits
107+
108+
Using Context classes provides several key benefits:
109+
110+
1. **Resource Efficiency**: Share expensive resources (like database engines) across multiple tasks in the same worker thread, reducing initialization overhead.
111+
112+
2. **Task Isolation**: Each task gets its own isolated metadata via ContextVars, ensuring data integrity even with concurrent execution.
113+
114+
3. **Type Safety**: Full type hint support means your IDE and type checkers understand the context structure.
115+
116+
4. **Clean API**: The context parameter is automatically injected, so your task functions have a clean public interface without exposing implementation details.
117+
118+
5. **Flexibility**: Subclass `Context` to create domain-specific contexts tailored to your application's needs.
119+
120+
!!! tip "Avoiding Event Loop Issues in Multi-threaded Environments"
121+
122+
FluxQueue's multi-threaded Tokio runtime can cause issues with async database libraries like `asyncpg` that throw errors such as "got future pending attached to a different loop" when resources are shared across threads.
123+
124+
By using the Context class with `thread_storage`, each executor in the worker gets its own database engine instance. Combined with Python's context managers, you can safely acquire database sessions and run queries without event loop conflicts. This ensures that each worker thread maintains its own isolated database connection pool, preventing cross-thread resource sharing issues.
125+
126+
## Async and Sync Support
127+
128+
Context classes work seamlessly with both synchronous and asynchronous tasks:
129+
130+
```python
131+
# Synchronous task with context
132+
@fluxqueue.task_with_context()
133+
def sync_task(ctx: Context, data: str):
134+
print(f"Processing {data} in task {ctx.metadata.task_id}")
135+
process(data)
136+
137+
# Async task with context
138+
@fluxqueue.task_with_context()
139+
async def async_task(ctx: Context, data: str):
140+
print(f"Processing {data} in task {ctx.metadata.task_id}")
141+
await process_async(data)
142+
```
143+
144+
## Best Practices
145+
146+
1. **Use thread_storage for expensive resources**: Database engines, HTTP clients, and connection pools are perfect candidates for thread storage.
147+
148+
2. **Keep metadata read-only**: The metadata property is read-only for a reason - don't try to modify it.
149+
150+
3. **Subclass for domain logic**: Create custom context classes when you have domain-specific resources or logic that multiple tasks share.
151+
152+
4. **One context parameter per task**: Each task function should have exactly one context parameter, typed as `Context` or a subclass.
153+
154+
5. **Initialize resources lazily**: Check if resources exist in `thread_storage` before creating them to avoid unnecessary initialization.

docs/features/index.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# Features
2+
3+
Learn about FluxQueue's features and how to use them.
4+
5+
## Feature Documentation
6+
7+
- **[Context Classes](context.md)** - Access task metadata and manage thread-persistent resources

docs/index.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Welcome to FluxQueue documentation. FluxQueue is a lightweight, resource-efficie
1919

2020
## What is FluxQueue?
2121

22-
FluxQueue is a task queue for Python that gets out of your way. The Rust core makes the process fast with less overhead, least dependencies, and most importantly, less memory usage. Tasks are managed through Redis.
22+
FluxQueue is a task queue for Python that gets out of your way. Built on a multi-threaded Tokio runtime, FluxQueue delivers high throughput while maintaining low memory usage. The Rust core ensures minimal overhead and dependencies, making it an efficient solution for background task processing. Tasks are managed through Redis.
2323

2424
## Key Features
2525

@@ -31,6 +31,7 @@ FluxQueue is a task queue for Python that gets out of your way. The Rust core ma
3131
- **Multiple Queues**: Organize tasks across different queues
3232
- **Simple API**: Decorator-based interface that feels natural in Python
3333
- **Type Safe**: Full type hints support
34+
- **Context Classes**: Access task metadata and manage thread-persistent resources with the Context class
3435

3536
## Requirements
3637

docs/release-notes.md

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
# Release Notes
2+
3+
All notable changes to FluxQueue will be documented in this file.
4+
5+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7+
8+
## [Unreleased]
9+
10+
### Added
11+
12+
- **Context Classes**: New `Context` class for accessing task metadata and managing thread-persistent resources ([#114](https://github.com/CCXLV/fluxqueue/pull/114))
13+
- `@fluxqueue.task_with_context()` decorator for tasks that need context access
14+
- `Context.metadata` property for accessing task execution information (task ID, retry count, etc.)
15+
- `Context.thread_storage` property for sharing resources across tasks in the same worker thread
16+
- Support for custom context classes by subclassing `Context`
17+
- Prevents event loop issues in multi-threaded environments (e.g., asyncpg "got future pending attached to a different loop" errors)
18+
- Works with both synchronous and asynchronous tasks
19+
- Client library version check before worker initialization ([#128](https://github.com/CCXLV/fluxqueue/pull/128))
20+
- Tests to cover the context feature ([#130](https://github.com/CCXLV/fluxqueue/pull/130))
21+
22+
### Changed
23+
24+
- Moved function calls to dispatcher ([#116](https://github.com/CCXLV/fluxqueue/pull/116))
25+
- Improved executor startup speed ([#117](https://github.com/CCXLV/fluxqueue/pull/117))
26+
- Made startup logs more clear ([#118](https://github.com/CCXLV/fluxqueue/pull/118))
27+
- Improved examples documentation ([#119](https://github.com/CCXLV/fluxqueue/pull/119))
28+
- Fixed worker installation instructions in README ([#120](https://github.com/CCXLV/fluxqueue/pull/120))
29+
- Bumped pyo3 dependency versions ([#121](https://github.com/CCXLV/fluxqueue/pull/121))
30+
- Improved client docstrings ([#122](https://github.com/CCXLV/fluxqueue/pull/122))
31+
- Improved `_run_async_task` docstring for clarity ([#126](https://github.com/CCXLV/fluxqueue/pull/126))
32+
- Various fixes and updates ([#124](https://github.com/CCXLV/fluxqueue/pull/124))
33+
34+
### Fixed
35+
36+
- Fixed tasks with the base Context class ([#123](https://github.com/CCXLV/fluxqueue/pull/123))
37+
- Fixed client library version check for older workers ([#129](https://github.com/CCXLV/fluxqueue/pull/129))
38+
- Reverted disallowing `_Context` as context name ([#127](https://github.com/CCXLV/fluxqueue/pull/127))
39+
40+
## [0.2.1] - 2026-02-21
41+
42+
### Changed
43+
44+
- Moved examples to docs ([#110](https://github.com/CCXLV/fluxqueue/pull/110))
45+
- Moved core to crates directory ([#111](https://github.com/CCXLV/fluxqueue/pull/111))
46+
- Renamed Rust core module ([#112](https://github.com/CCXLV/fluxqueue/pull/112))
47+
- Improved task decorator type inference ([#113](https://github.com/CCXLV/fluxqueue/pull/113))
48+
49+
## [0.2.0] - 2026-02-17
50+
51+
### Added
52+
53+
- Logs after task finishes ([#80](https://github.com/CCXLV/fluxqueue/pull/80))
54+
- Python version badges in README and classifiers/keywords in pyproject.toml ([#84](https://github.com/CCXLV/fluxqueue/pull/84))
55+
- Unit and integration tests ([#90](https://github.com/CCXLV/fluxqueue/pull/90))
56+
- Support for Windows and macOS ([#94](https://github.com/CCXLV/fluxqueue/pull/94))
57+
- Tests status badge in README ([#92](https://github.com/CCXLV/fluxqueue/pull/92))
58+
59+
### Changed
60+
61+
- Updated way of running async task functions ([#83](https://github.com/CCXLV/fluxqueue/pull/83))
62+
- Improved README clarity and documentation ([#85](https://github.com/CCXLV/fluxqueue/pull/85), [#86](https://github.com/CCXLV/fluxqueue/pull/86), [#87](https://github.com/CCXLV/fluxqueue/pull/87))
63+
- Updated get_functions.py script to raise exception on duplication ([#78](https://github.com/CCXLV/fluxqueue/pull/78))
64+
- Bumped worker version to 0.2.0-beta.4 ([#95](https://github.com/CCXLV/fluxqueue/pull/95))
65+
- Updated pyproject description ([#108](https://github.com/CCXLV/fluxqueue/pull/108))
66+
67+
### Fixed
68+
69+
- Fixed executors heartbeat flaw on startup ([#82](https://github.com/CCXLV/fluxqueue/pull/82))
70+
- Fixed test_path_to_module_path to work on Windows ([#93](https://github.com/CCXLV/fluxqueue/pull/93))
71+
- Fixed various workflow files (release-worker, build-worker, publish workflows) ([#96](https://github.com/CCXLV/fluxqueue/pull/96), [#97](https://github.com/CCXLV/fluxqueue/pull/97), [#98](https://github.com/CCXLV/fluxqueue/pull/98), [#99](https://github.com/CCXLV/fluxqueue/pull/99), [#100](https://github.com/CCXLV/fluxqueue/pull/100), [#101](https://github.com/CCXLV/fluxqueue/pull/101), [#102](https://github.com/CCXLV/fluxqueue/pull/102), [#105](https://github.com/CCXLV/fluxqueue/pull/105), [#106](https://github.com/CCXLV/fluxqueue/pull/106))
72+
- Fixed license name in pyproject.toml ([#107](https://github.com/CCXLV/fluxqueue/pull/107))
73+
- Fixed pyproject classifiers ([#109](https://github.com/CCXLV/fluxqueue/pull/109))
74+
75+
[Unreleased]: https://github.com/CCXLV/fluxqueue/compare/v0.3.0rc1...HEAD
76+
[0.3.0-rc1]: https://github.com/CCXLV/fluxqueue/compare/v0.2.1...v0.3.0rc1
77+
[0.2.1]: https://github.com/CCXLV/fluxqueue/compare/v0.2.0...v0.2.1
78+
[0.2.0]: https://github.com/CCXLV/fluxqueue/compare/v0.2.0-beta.4...v0.2.0

mkdocs.yml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,9 @@ plugins:
6060

6161
nav:
6262
- FluxQueue: index.md
63+
- Features:
64+
- features/index.md
65+
- features/context.md
6366
- Learn:
6467
- tutorial/index.md
6568
- tutorial/installation.md
@@ -80,6 +83,7 @@ nav:
8083
- api/fluxqueue.md
8184
- api/environment.md
8285
- About: about.md
86+
- Release Notes: release-notes.md
8387

8488
markdown_extensions:
8589
- pymdownx.highlight:

0 commit comments

Comments
 (0)