CQRS & Dispatcher Patterns
Relevant source files
The following files were used as context for generating this wiki page:
The Command Query Responsibility Segregation (CQRS) and Dispatcher patterns are core architectural pillars of the FLEXT platform. These patterns decouple the initiation of an action from its execution, allowing the system to separate read operations (Queries) from write operations (Commands). This separation ensures that the business logic remains clean, testable, and maintainable.
In the FLEXT ecosystem, the FlextDispatcher acts as the central hub for routing these messages to their appropriate handlers. This mechanism is often paired with Railway-Oriented Programming (ROP) to handle results and errors consistently across the web and core layers.
Sources: guides/getting-started.md:144-148, guides/development.md:120-125
Architectural Components
The CQRS implementation in FLEXT consists of three primary components: the Message (Command or Query), the Handler, and the Dispatcher.
Messages: Commands and Queries
Messages are simple data structures, typically implemented as dataclasses or Pydantic models, that represent an intent.
- Commands: Represent an intent to change the state of the system (e.g.,
CreateUserCommand). - Queries: Represent an intent to retrieve data without side effects (e.g.,
GetUserQuery).
Sources: guides/getting-started.md:148-163
The Dispatcher (FlextDispatcher)
The Dispatcher serves as a registry and execution engine. It maintains a mapping between message types and the specific service methods responsible for handling them. When a message is dispatched, the FlextDispatcher identifies the correct handler and executes it, returning a Result object.
Sources: guides/getting-started.md:175-184
Handlers
Handlers are methods within services that contain the actual business logic. They receive a specific Command or Query and return a p.Result, adhering to the Railway-Oriented Programming pattern.
Sources: guides/getting-started.md:165-173, guides/development.md:105-115
Data Flow and Execution
The flow of a request through the CQRS system follows a structured path from the initial call to the final result.
This diagram illustrates the lifecycle of a message within the dispatcher system.
Sources: guides/getting-started.md:175-184, src/flext_web/services/handlers.py
Dispatcher Sequence
The following sequence diagram shows the interaction between the application code, the dispatcher, and the underlying service.
Sources: guides/getting-started.md:175-184
Implementation Patterns
Registration and Dispatching
To use the CQRS pattern, services must first register their methods with the dispatcher instance.
| Step | Action | Implementation Example |
|---|---|---|
| 1 | Define Message | @dataclass class CreateUserCommand: ... |
| 2 | Create Service | class UserService: def create_user(self, cmd): ... |
| 3 | Register | dispatcher.register_handler(CreateUserCommand, user_svc.create_user) |
| 4 | Execution | result = dispatcher.dispatch(CreateUserCommand(...)) |
Sources: guides/getting-started.md:148-184
Integration with Web Layers
In flext-web, handlers are often integrated into the service layer to process web-specific messages or messages originating from HTTP requests. The unified model pattern ensures that these messages are typed and validated before reaching the dispatcher.
# Example of a service handler in the web context
class FlextWebHandlers:
def handle_web_message(self, msg: WebMessage) -> p.Result[WebResponse]:
# Implementation logic
pass
Sources: src/flext_web/services/handlers.py, src/flext_web/_models/_web_message.py, development.md:15-20
Testing CQRS Components
Testing in the CQRS framework is simplified because commands and queries are isolated. Unit tests can exercise handlers directly, while integration tests can verify the dispatcher's registry and routing.
- Unit Tests: Focus on the logic within the service handler using mocked inputs.
- Integration Tests: Verify that
FlextDispatchercorrectly routes a registered command to its handler and returns the expectedp.Result.
Sources: guides/testing.md:120-140, guides/development.md:155-165
Summary
The CQRS and Dispatcher patterns in FLEXT provide a robust architecture for managing complex data interactions. By utilizing the FlextDispatcher to route typed Commands and Queries to specific Service Handlers, the project achieves a high degree of separation of concerns. This approach, combined with Railway-Oriented Programming, ensures that every operation produces a predictable Result, facilitating easier debugging, testing, and system evolution.