Skip to content

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