Lifecycle entities ¶
Internally RKD has three types of objects that are used across the application - Task creation, Task usage declaration, Task execution scheduling.
1) Task Creation ¶
TaskInterface
implementations are considered to provide
importable Tasks
to be used in any automation project.
Example: I have
PostgreSQLRunTask
and I import it as
:pgsql:start
# ...
class RenderDirectoryTask(TaskInterface):
"""Renders *.j2 files recursively in a directory to other directory"""
def get_name(self) -> str:
return ':directory-to-directory'
def get_group_name(self) -> str:
return ':j2'
def execute(self, context: ExecutionContext) -> bool:
# ...
Tasks should be defined mainly as part of installable libraries via PyPI, but could be also defined in local repository.
2) Task usage declaration - importing & preconfiguring Tasks in project code ¶
TaskDeclaration
declares that imported
TaskInterface
implementation would be used in our automation project
under some name, with some environment variables, custom workspace and other little customizations that does not involve changing the code of imported Task.
Pipeline
,
PipelineTask
and
PipelineBlock
defines complete Pipelines, with error handling, notifications, list of Tasks to execute.
That’s called static declaration of reproducible usage. Tasks are imported into a project defined in code, each Task is preconfigured and ready to be used in reproducible way.
from rkd.core.api.syntax import Pipeline, PipelineTask as Task, PipelineBlock as Block, TaskDeclaration
from rkd.core.standardlib.core import DummyTask
from rkd.core.standardlib.shell import ShellCommandTask
IMPORTS = [
TaskDeclaration(ShellCommandTask(), internal=True)
]
PIPELINES = [
Pipeline(
name=':example',
to_execute=[
Block(rescue='...', tasks=[
Task('...'),
]),
Task('...'),
]
)
]
3) Runtime Task scheduling ¶
Imported Tasks and declared for usage in a project are processed, when executed. This later stage is invisible to end-user and is performed internally on runtime, the entities are not known to the user.
Internally RKD must wrap any
TaskDeclaration
and process
Pipeline
into lower-level entities on first stage - resolving & compilation stage.
TaskDeclaration
is wrapped by
DeclarationScheduledToRun
that
mixes
environment, arguments and other options
declared in code with everything that
exists during execution that takes place now.
Pipeline
is translated into
GroupDeclaration
and associated
ArgumentBlock
objects which are no longer strings like
:db:start
--listen=5432
, but are separate
TaskDeclaration
objects.
There are all
@rescue
and
@error
modifiers resolved into objects, so everything is calculated on very early stage and therefore can be validated without disrupting later execution by any simple errors.
Each
TaskDeclaration
in Pipeline is wrapped into
DeclarationBelongingToPipeline
which acts very similar to
DeclarationScheduledToRun
, but it was named differently
to distinct between something that was declared in the code (
DeclarationBelongingToPipeline
) from something that contains a set of information how the user invoked the command from shell (
DeclarationScheduledToRun
)