Service
Service
A service is the technical authority for a business capability. And it is the exclusive owner of a certain subset of the business data. It centralizes and organizes domain operations, enforces business rules, and coordinates workflows.
The Service
serves as an entry point for the service layer and provides a simple way to
build stateless logic for executing domain operations.
A service should be modeled with ubiquitous language. This means that the names of handler
functions should reflect the domain operations that the service is responsible for. Keep
this in mind when naming the functions that will be registered as handlers, since the Service
class provides a method to call the handlers by their registered name. This is useful for example
when building REST APIs with Command Query Segregation (CQS) and you want to invoke a handler based
on the action they perfom (aka. The handler's name).
A naming generator can be provided to the Service
constructor in order to customize the function names
to the ubiquitous language of the domain. The default generator transforms the function name from snake_case
to kebab-case.
Methods:
Name | Description |
---|---|
handler |
Decorator for registering a function as a handler. |
execute |
Executes the handler associated with a given action. |
Example
from torch import cuda
from torch.nn import Module
from torch.utils.data import DataLoader
from pymsgbus import Depends
from pymsgbus import Service
service = Service()
def device() -> str:
raise NotImplementedError('Override this function to return the device')
@service.handler
def train(model: Module, data: DataLoader, device: str = Depends(device)):
# Your training logic here
...
service.override(device, lambda: 'cuda' if cuda.is_available() else 'cpu')
service.execute('train', model, dataloader)
#or simply call train(model, dataloader) it will inject dependencies anyway.
dependency_overrides
property
An entry point for overriding the dependencies for the service. This is useful for late binding, testing and changing the behavior of the service in runtime.
Returns:
Name | Type | Description |
---|---|---|
dict |
dict
|
A dictionary of the dependency map. |
execute(action, *args, **kwargs)
Executes the handler associated with the given action. The action is the generated name
from the handler function to be executed. The name is generated by the generator
function
provided to the service, which defaults to transforming the function name from snake case
to kebab case.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
action
|
str
|
The action to execute the handler for. |
required |
Raises:
Type | Description |
---|---|
KeyError
|
If the handler for the action is not found. |
Returns:
Name | Type | Description |
---|---|---|
Any |
Any
|
Whatever the handler returns. |
handler(wrapped)
Decorator for registering a function as a handler in the service. The handler is registered with the name of the function as the key. The handler is also injected with the dependencies provided by the service.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
wrapped
|
Callable[..., Any]
|
The function to be registered as a handler. |
required |
Returns:
Type | Description |
---|---|
Callable[..., Any]
|
Callable[..., Any]: The injected handler function. |
override(dependency, implementation)
Overrides a dependency with an implementation.
Parameters:
Name | Type | Description | Default |
---|---|---|---|
dependency
|
Callable
|
The dependency function to override. |
required |
implementation
|
Callable
|
The implementation of the function. |
required |