Documentation Index
Fetch the complete documentation index at: https://mintlify.com/Indroic/HexCore/llms.txt
Use this file to discover all available pages before exploring further.
ITaskEnqueuer is HexCore’s output port for delegating work to an external task queue. When a command or event handler is decorated with @background_command or @background_handler, the appropriate bus dispatches the serialised payload to the enqueuer instead of executing the handler inline. Two concrete adapters are included: CeleryEnqueuer (sync Celery, run via asyncio.to_thread) and ProcrastinateEnqueuer (async PostgreSQL-backed).
ITaskEnqueuer
hexcore.domain.cqrs.task_queues.ITaskEnqueuer
Abstract base class (output port) that all task queue adapters must implement.
Abstract methods
Enqueues a serialised domain command for background execution.
command_name is the qualified command class name (e.g. "CreateUserCommand"). payload is the pre-serialised dict produced by ISerializer.serialize().Enqueues a serialised domain event for generic distribution. Both
CeleryEnqueuer and ProcrastinateEnqueuer provide a no-op default; use enqueue_handler for targeted delivery.Enqueues a specific event handler for background execution.
handler_name is the handler’s __cqrs_handler_name__ attribute (its qualified import path). This is the primary method used by Smart Routing.Enqueues a generic background task decorated with
@background_task. task_name is the task’s __cqrs_task_name__ attribute. payload is passed as **kwargs to the task function.CeleryEnqueuer
hexcore.infrastructure.task_queues.celery_adapter.CeleryEnqueuer
Adapts ITaskEnqueuer to Celery’s synchronous send_task API. Because ITaskEnqueuer is fully async and Celery’s send_task blocks, each call uses asyncio.to_thread to avoid freezing the event loop in FastAPI or other async frameworks.
Constructor
A configured
Celery application instance. The enqueuer calls app.send_task(name, kwargs=..., queue=...).Method implementations
| Method | Celery task name | Kwargs sent |
|---|---|---|
enqueue_command | hexcore.process_command | {"payload": payload} |
enqueue_event | (no-op) | — |
enqueue_handler | hexcore.process_handler | {"handler_name": handler_name, "payload": payload} |
enqueue_task | hexcore.process_task | {"task_name": task_name, "payload": payload} |
Example
register_hexcore_celery_tasks()
hexcore.infrastructure.task_queues.celery_adapter.register_hexcore_celery_tasks
Celery application instance. Call this in your celery.py worker module so that the worker knows how to handle messages produced by CeleryEnqueuer.
The Celery application to register tasks on.
The
CQRSConsumer instance wired with the local in-memory buses and serialiser. Its process_* methods are called synchronously via asyncio.run() inside each task.Registered tasks
| Task name | Celery task signature | Delegates to |
|---|---|---|
hexcore.process_command | process_command(payload: dict) | consumer.process_command(payload) |
hexcore.process_handler | process_handler(handler_name: str, payload: dict) | consumer.process_handler(handler_name, payload) |
hexcore.process_task | process_task(task_name: str, payload: dict) | consumer.process_task(task_name, payload) |
ProcrastinateEnqueuer
hexcore.infrastructure.task_queues.procrastinate_adapter.ProcrastinateEnqueuer
Adapts ITaskEnqueuer to Procrastinate’s fully-async defer_async API. No thread offloading is required — each method is a native coroutine.
Constructor
A configured
procrastinate.App instance (connected to PostgreSQL via asyncpg). The enqueuer uses app.configure_task(name=..., queue=...).defer_async(...).Method implementations
| Method | Task name | Args deferred |
|---|---|---|
enqueue_command | hexcore.process_command | payload=payload |
enqueue_event | (no-op) | — |
enqueue_handler | hexcore.process_handler | handler_name=handler_name, payload=payload |
enqueue_task | hexcore.process_task | task_name=task_name, payload=payload |
register_hexcore_procrastinate_tasks()
| Task name | Async task signature |
|---|---|
hexcore.process_command | process_command(payload: dict) |
hexcore.process_handler | process_handler(handler_name: str, payload: dict) |
hexcore.process_task | process_task(task_name: str, payload: dict) |
CQRSConsumer
hexcore.infrastructure.workers.consumer.CQRSConsumer
Universal CQRS message consumer for worker processes. Receives serialised payloads from any task queue backend, deserialises them using the configured ISerializer, and dispatches the resulting commands or events to local in-memory buses. Runs inside the worker process, which maintains its own handler registry.
Constructor
The local command bus (typically
InMemoryCommandBus) with all command handlers registered. Receives deserialised commands via dispatch().The local event bus (typically
InMemoryEventBus). Receives deserialised events via publish().The serialiser instance (e.g.
PydanticSerializer) used to reconstruct domain objects from raw dict payloads.Methods
Deserialises
payload into a Command instance and dispatches it to the local command_bus. Logs and re-raises on failure.Deserialises
payload into a DomainEvent instance and publishes it to the local event_bus. All locally subscribed handlers for that event type are invoked.Deserialises
payload into a DomainEvent, then resolves handler_name as a Python qualified import path (e.g. "myapp.events.on_user_created") and calls it directly. This is the target of enqueue_handler Smart Routing — only the single decorated handler runs, not all subscribers.Resolves
task_name as a qualified import path and calls it with **payload as keyword arguments. Used by enqueue_task for generic background functions.PydanticSerializer
hexcore.infrastructure.cqrs.pydantic_serializer.PydanticSerializer
Default ISerializer implementation for HexCore CQRS. Serialises any Pydantic BaseModel subclass to a dict envelope carrying the fully-qualified type name and reconstructs it on the other end using model_validate.
Wire format
Methods
Produces the wire envelope.
__type__ is f"{module}.{qualname}". __data__ is message.model_dump(mode="json").Resolves
__type__ via importlib.import_module + getattr, then reconstructs the object with cls.model_validate(__data__). Raises DeserializationError if __type__ or __data__ are missing, the type cannot be imported, or validation fails.