Photons Task Classο
The tasks that are registered with the photons_app.tasks.task_register will
become instances of the photons_app.tasks.Task class.
- class photons_app.tasks.Task(*args, **kwargs)ο
Responsible for managing the life cycle of a photons program
It has on it by default the following attributes:
- instantiated_name
The name that was used when this task was created
- collector
The Collector used for this Photons session
- photons_app
The PhotonsApp object associated with this Photons session
- task_holder
A
photons_app.helpers.TaskHolderinstance that wraps the execution of the task
Extra attributes may be added using
dictobj.Fieldobjects via delfick_project.norms.The life cycle of the task is contained within the
runmethod, which is responsible for managing thetask_holder, runningexecute_taskand ensuringpostis run whenexecute_taskis done regardless of whether it raised an exception or not.execute_taskmust be implemented and is where the body of the task should go.postis an optional hook that may be implemented to execute code regardless of howexecute_taskfinished.
The task_register has on it some helpful methods for creating fields on a
task:
from photons_app.tasks import task_register as task
from delfick_project.norms import sb
@task
class my_amazing_task(task.Task):
# This will use ``collector.target_register.resolve`` to get a target
# object for use in the task
#
# ``task.requires_target`` will ensure that if no ``t1`` was provided
# then an error will be raised complaining it is required
#
# ``task.provides_target`` will mean ``t2`` will be given the value
# ``delfick_project.norms.sb.NotSpecified`` if no value was given.
#
# The options to both include ``target_types`` which is a list of type
# that are valid; and ``target_names`` which is a list of target names
# that are valid.
t1 = task.requires_target(target_types=["lan"])
t2 = task.provides_target(target_types=["lan"])
# These helpers are for the reference
# The following two lines are equivalent
r1 = task.provides_reference()
r1 = task.Field(sb.any_spec(), wrapper=sb.optional_spec)
# And these two are equivalent
r1 = task.requires_reference()
r1 = task.Field(sb.any_spec(), wrapper=sb.required_spec)
# Both of them however also have a ``special`` option
# where, if there is a value that can be used, photons uses
# ``collector.reference_object(val)`` on that value
# Note that for ``provides_reference``, this means not specifying a value
# will get us a ``photons_app.special.FoundSerials`` object.
r2 = task.requires_reference(special=True)
r3 = task.provides_reference(special=True)
# Finally these two lines are equivalent
a = task.provides_artifact()
a = task.Field(sb.any_spec, wrapper=sb.optional_spec)
async def execute_task(self, **kwargs):
# In here ``self`` will have all the values above, so
# self.t1 and self.t2 would be LanTarget objects
# self.r1 would be either sb.NotSpecified or a string
# self.r2 and self.r3 would be SpecialReference objects
# self.a would be either sb.NotSpecified or a string
# And also self.collector, self.photons_app and self.task_holder
...
Life cycleο
The life cycle of the task depends on whether you inherit from task.Task or
task.GracefulTask.
For task.Task:
self.task_holder is initialized
execute_task is called
Ends if the function returns or raises an exception
Ends if
photons_app.final_futureis resolvedEnds on unix machines if the application receives a SIGTERM signal
Ends if the program receives a KeyboardInterrupt (ctrl-c)
The asyncio task representing execute_task may not be finished yet when any of those end conditions are met. Because it is not a GracefulTask photons tell that asyncio task to cancel, which causes an
asyncio.CancelledErrorto be raised in the codeThe asyncio task is waited to finish any exception handlers or finally blocks
The post method is called
Photons waits for the
task_holderto finish any remaining asyncio tasks. Note that it is up to the programmer to ensure these tasks finish ifphotons_app.final_futureis resolved.The functions in the
photons_app.cleanersarray are called and errors from those are ignoredAny photons target that was used is told to cleanup any resources
Any remaining tasks and async generators are closed and cleaned up, and the asyncio loop photons used is closed and deleted
For task.GracefulTask:
self.task_holder is initialized
execute_task is called
Ends if the function returns or raises an exception
Ends if
photons_app.final_futureis resolvedEnds if the program receives a KeyboardInterrupt (ctrl-c)
difference SIGTERM will resolve
photons_app.graceful_final_futurerather thanphotons_app.final_future.
The asyncio task representing execute_task may not be finished yet when any of those end conditions are met.
difference Because itβs a GracefulTask, the assumption is that if graceful_final_future is resolved then the task will shut itself down without needing to be cancelled. So photons ensures that
graceful_final_futureis resolved, and leaves the asyncio task forexecute_taskto continue without being cancelled.The post method is called
Photons waits for the
task_holderto finish any remaining asyncio tasks. Note that it is up to the programmer to ensure these tasks finish ifphotons_app.graceful_final_futureis resolved.difference
photons_app.final_futureis cancelled if it remains unresolved andphotons_app.graceful_final_futurewas resolved with a cancellation or SIGTERM. Otherwise final_future is resolved how graceful_final_future has been resolved.The functions in the
photons_app.cleanersarray are then called and errors from those are ignoredAny photons target that was used is told to cleanup any resources
Any remaining tasks and async generators are closed and cleaned up, and the asyncio loop photons used is closed and deleted
The task will raise the following exceptions based on these events:
SIGTERM ensures a
photons_app.errors.ApplicationStoppedis raised unlessGracefulTaskwas used.KeyboardInterrupt raises
photons-app.errors.UserQuitA
asyncio.CancelledErrorbeing raised will result inphotons_app.errors.ApplicationCancelledbeing raised.
Note
once the post handle is called, any exception from execute_task
or post will be passed onto the task_holder and in affect cancel
anything on it.
The exception to this is tasks using GracefulTask will not pass on an
ApplicationStopped exception, which is what the execute_task will
raise upon getting a SIGTERM.