|
1 | 1 | # Changelog |
2 | 2 |
|
| 3 | +## v0.2.0rc2 |
| 4 | + |
| 5 | +Second release candidate for 0.2.0. Completes the async migration and |
| 6 | +stabilizes the worker pool architecture. |
| 7 | + |
| 8 | +### Breaking Changes |
| 9 | + |
| 10 | +**Fully async database layer** |
| 11 | +- `configure_engine()` and `get_session()` now require an async SQLAlchemy engine (`AsyncEngine`) and return `AsyncSession` |
| 12 | +- Database URLs must use async drivers (e.g. `sqlite+aiosqlite://`, `postgresql+asyncpg://`) |
| 13 | +- `sqlalchemy[asyncio]` is now a core dependency; `aiosqlite` added as dev dependency |
| 14 | + |
| 15 | +**Async activity query API** |
| 16 | +- `activity.list()`, `activity.detail()`, and `activity.count_active()` are now async and accept `AsyncSession` |
| 17 | +- Activity handlers are now async (`async def __call__`) |
| 18 | + |
| 19 | +**Removed `session` parameter from activity mutations** |
| 20 | +- `activity.create()`, `activity.update()`, `activity.complete()`, and `activity.error()` no longer accept a `session` parameter — the handler owns its own session lifecycle |
| 21 | + |
| 22 | +**Queue priority parameter** |
| 23 | +- `BaseQueueBackend.push()` signature changed from `high_priority: bool` to `priority: Priority | None` |
| 24 | +- Affects Redis, Kafka, and any custom queue backend implementations |
| 25 | + |
| 26 | +### New Features |
| 27 | + |
| 28 | +**CLI entrypoint** |
| 29 | +- New `agentexec` CLI command via `[project.scripts]` |
| 30 | + |
| 31 | +**Activity model `create()` classmethod** |
| 32 | +- `Activity.create()` encapsulates record + initial log entry creation in one async call |
| 33 | + |
| 34 | +**Async engine disposal** |
| 35 | +- `dispose_engine()` ensures the async engine's background threads exit cleanly on shutdown |
| 36 | + |
| 37 | +### Architecture Changes |
| 38 | + |
| 39 | +**Worker pool refactor** |
| 40 | +- Workers now use the `spawn` multiprocessing start method with explicit context — no inherited state |
| 41 | +- `StateEvent` replaced with stdlib `multiprocessing.Event` — removes dependency on the state backend for shutdown coordination |
| 42 | +- Event handling and scheduling extracted into `_EventHandler` and `_Scheduler` classes |
| 43 | +- Worker processes are now daemonic with `SIGINT` ignored — clean shutdown driven by the event |
| 44 | +- `pool.start()` handles `CancelledError` directly for Ctrl+C shutdown |
| 45 | + |
| 46 | +**Logging overhaul** |
| 47 | +- Removed `worker/logging.py` and `core/logging.py` — all modules use stdlib `logging.getLogger(__name__)` |
| 48 | +- Spawned workers bootstrap a `StreamHandler` on the root logger so logs reach stderr |
| 49 | +- Pool messages use `logger.info`/`logger.error` instead of `print()` |
| 50 | + |
| 51 | +### Bug Fixes |
| 52 | + |
| 53 | +- Fixed crash when worker receives a task for an unregistered task name (now logs error and skips) |
| 54 | +- Failed tasks now log full tracebacks via `logger.exception` instead of `logger.error` |
| 55 | +- Kafka consumer handles `None` message values without crashing |
| 56 | +- `ActivityUpdated.status` is now `Status` enum instead of raw string |
| 57 | +- `raise e` instead of bare `raise` in task execution for clearer tracebacks |
| 58 | + |
| 59 | +### Improvements |
| 60 | + |
| 61 | +- Dependency groups use PEP 735 `[dependency-groups]` instead of `[tool.uv]` |
| 62 | +- Ruff line-length increased to 110 |
| 63 | +- Removed verbose docstring examples and redundant comments throughout activity models |
| 64 | +- `selectinload` for eager loading of activity logs in `get_by_agent_id` |
| 65 | +- Redis backend adds `type: ignore` annotations for redis-py async stubs |
| 66 | + |
| 67 | +## v0.2.0rc1 |
| 68 | + |
| 69 | +First release candidate for 0.2.0. Major refactor of the backend, queue, |
| 70 | +activity, and worker systems. |
| 71 | + |
| 72 | +### Breaking Changes |
| 73 | + |
| 74 | +**Backend module restructure** |
| 75 | +- `agentexec.state.redis_backend` renamed to `agentexec.state.redis` — update `AGENTEXEC_STATE_BACKEND` if set explicitly |
| 76 | +- `AGENTEXEC_QUEUE_NAME` renamed to `AGENTEXEC_QUEUE_PREFIX` (old name still accepted as alias) |
| 77 | + |
| 78 | +**Async activity API** |
| 79 | +- Activity functions are now async: `await ax.activity.create(...)`, `await ax.activity.update(...)`, etc. |
| 80 | + |
| 81 | +**Task context serialization** |
| 82 | +- `Task.context` is now `Mapping[str, Any]` (raw dict), not a typed BaseModel — hydration happens at execution time |
| 83 | +- `Task.create()` is now async |
| 84 | + |
| 85 | +**Removed APIs** |
| 86 | +- `set_global_session`/`get_global_session`/`remove_global_session` — use `configure_engine`/`get_session` |
| 87 | +- `state.backend.publish`/`subscribe` (pubsub), `index_add`/`index_range`/`index_remove`, `clear`, `configure` |
| 88 | + |
| 89 | +### New Features |
| 90 | + |
| 91 | +**Partitioned Redis queues** |
| 92 | +- Tasks with `lock_key` route to dedicated partition queues with per-partition locking and SCAN-based fair dequeue |
| 93 | + |
| 94 | +**Activity handler pattern** |
| 95 | +- Pluggable persistence via `PostgresHandler` (default) and `IPCHandler` (worker processes) |
| 96 | + |
| 97 | +**Task retry** |
| 98 | +- Failed tasks requeue as high priority with `AGENTEXEC_MAX_TASK_RETRIES` (default 3) |
| 99 | + |
| 100 | +**Kafka backend (experimental)** |
| 101 | +- `pip install agentexec[kafka]` for queue and schedule via Kafka |
| 102 | + |
| 103 | +**Typed worker IPC** |
| 104 | +- `TaskFailed`, `LogEntry`, `ActivityUpdated` messages over `multiprocessing.Queue` |
| 105 | + |
| 106 | +**Schedule composite keys** |
| 107 | +- `{task_name}:{cron}:{context_hash}` for unique schedule identity |
| 108 | + |
| 109 | +### Improvements |
| 110 | + |
| 111 | +- Class-based backend architecture with ABCs (`BaseStateBackend`, `BaseQueueBackend`, `BaseScheduleBackend`) |
| 112 | +- `Task` is pure data, `TaskDefinition` owns behavior |
| 113 | +- Session management via `configure_engine`/`get_session` (Pool owns the engine) |
| 114 | +- Status enum extracted to `activity/status.py` (no SQLAlchemy dependency) |
| 115 | + |
3 | 116 | ## v0.1.7 |
4 | 117 |
|
5 | 118 | ### New Features |
|
0 commit comments