Skip to content

4. Pretreatment for projects

Sometimes it is necessary to prepare a project before it is moved to the actual state. This could mean that the project data needs to be manipulated, that emails need to be sent or something completely different.

Pretreatments are enabled by default but have no logic implemented, meaning every project simply passes through without any actions taken. To add pretreatment logic, you have to overwrite the state’s method pretreatment():

custom/MyState.py
class MyState(BaseState):
...
@classmethod
def pretreatment(cls, project: Project) -> bool:
...

This method receives the project the pretreatment has to be executed on. It returns a boolean, indicating if the pretreatment was successful or not.

This example shows a pretreatment that adds default resources for test projects in case that it did not request any:

custom/MyState.py
from perseus.datamanager import Project, DatabaseManager, ResourceValue
class MyState(BaseClass):
...
@classmethod
def pretreatment(cls, project: Project) -> bool:
DEFAULT_RESOURCES_TEST_PROJECT = {
"cluster_cpu_h": 25000,
"cluster_gpu_h": 1000,
"cluster_fpga": 500,
}
if project.project_type == "test":
if len(project.requested_resources) == 0:
db_manager = DatabaseManager()
for (
resource_id,
default_value,
) in DEFAULT_RESOURCES_TEST_PROJECT.items():
project.requested_resources.append(
ResourceValue(
resource_id=resource_id,
value=default_value,
start=project.start,
end=project.end,
)
)
oid = db_manager.add_item(project)
if oid is None:
return False
return True

Sometimes, you maybe want to include pretreatments which can fail, i.e. when you need to call an API to create a user. In such a case, you can return False in the pretreatment() method. If that happens, the project will stay in the pretreatment cycle and the pretreatment will be executed again on it.

If you wish to add a more complex error handling, you can overwrite the state’s method pretreatment_error():

custom/MyState.py
class MyState(BaseState):
...
@classmethod
def pretreatment_error(cls, project: Project):
...

This method will be executed every time the pretreatment() method returns False. This means that, if the pretreatment for a project fails every time, this method will be executed basically every minute.

If you wish to i.e. send emails to notify about the failed pretreatment and not want to be potentially bombarded with emails, you can use the pretreatment_error() to also skip the pretreatment and move the project to the state:

custom/MyState.py
from perseus.state_machine import Event
class MyState(BaseState):
...
@classmethod
def pretreatment_error(cls, project: Project):
... # your error handling
MyState.trigger_internal_event(project, Event("PRETREATMENT"))

Pretreatments are enabled by default. This causes projects to always enter the pretreatment cycle, even if you did not specify any pretreatment logic.

If you want to disable pretreatments for a state completely, you need to overwrite the state’s method get_internal_state_machine() like this:

...
class MyState(BaseState):
...
@classmethod
def get_internal_state_machine(cls, project: Project | None = None) -> StateMachine:
return StateMachine(Path(("IN_STATE", None)))
...

This causes all projects to directly enter the state’s internal state IN_STATE, therefore skipping the internal state PRETREATMENT.