diff --git a/docs/source/extensions/example_extension/06_tasks_locks.py b/docs/source/extensions/example_extension/06_tasks_locks.py index 755158b5..1f1e680c 100644 --- a/docs/source/extensions/example_extension/06_tasks_locks.py +++ b/docs/source/extensions/example_extension/06_tasks_locks.py @@ -9,7 +9,6 @@ from labthings.server.decorators import ( PropertySchema, ThingAction, doc_response, - marshal_task, ) from labthings.server.schema import Schema from labthings.server import fields @@ -70,10 +69,8 @@ def timelapse(microscope, n_images, t_between): @ThingAction class TimelapseAPI(View): """ - Take a series of images in a timelapse, running as a background task + Take a series of images in a timelapse """ - - @marshal_task # Shorthand for marshaling with a pre-made Task object schema @use_args( { "n_images": fields.Integer( @@ -88,13 +85,11 @@ class TimelapseAPI(View): # Find our microscope component microscope = find_component("org.openflexure.microscope") - # Create and start "timelapse", running in a background task - task = taskify(timelapse)( + # Start "timelapse" + return timelapse( microscope, args.get("n_images"), args.get("t_between") ) - return task - ## Create extension diff --git a/docs/source/extensions/example_extension/07_ev_gui.py b/docs/source/extensions/example_extension/07_ev_gui.py index 1209669e..7ce55ebd 100644 --- a/docs/source/extensions/example_extension/07_ev_gui.py +++ b/docs/source/extensions/example_extension/07_ev_gui.py @@ -9,7 +9,6 @@ from labthings.server.decorators import ( PropertySchema, ThingAction, doc_response, - marshal_task, ) from labthings.server.schema import Schema from labthings.server import fields @@ -74,8 +73,6 @@ class TimelapseAPI(View): """ Take a series of images in a timelapse, running as a background task """ - - @marshal_task # Shorthand for marshaling with a pre-made Task object schema @use_args( { "n_images": fields.Integer( @@ -91,12 +88,10 @@ class TimelapseAPI(View): microscope = find_component("org.openflexure.microscope") # Create and start "timelapse", running in a background task - task = taskify(timelapse)( + return timelapse( microscope, args.get("n_images"), args.get("t_between") ) - return task - ## Extension GUI (OpenFlexure eV) # Alternate form without any dynamic parts diff --git a/docs/source/extensions/tasks_locks.rst b/docs/source/extensions/tasks_locks.rst index 38eb31e4..816a9d8a 100644 --- a/docs/source/extensions/tasks_locks.rst +++ b/docs/source/extensions/tasks_locks.rst @@ -15,7 +15,7 @@ We get around these issues by making use of background tasks, and component lock Background tasks ---------------- -Tasks are introduced to manage long-running functions in a way that does not block HTTP requests. Any function can be offloaded to a background task, and this is done through the :py:meth:`labthings.tasks.taskify` function, by calling ``taskify()(*args, **kwargs)``. +Tasks are introduced to manage long-running functions in a way that does not block HTTP requests. Any API Action will automatically run as a background task (that is, any View that subclasses `ActionView`, or uses the `@ThingAction` decorator). Internally, the ``tasks`` submodule stores a list of all requested tasks, and their states. This state stores the running status of the task (if itis idle, running, error, or success), information about the start and end times, a unique task ID, and, upon completion, the return value of the long-running function. @@ -23,7 +23,7 @@ By using tasks, a function can be started in the background, and it's return val API routes have been created to allow checking the state of all tasks (GET ``/tasks``), a particular task by ID (GET ``/tasks/``), and terminating or removing individual tasks (DELETE ``/tasks/``). -A special ``@marshal_task`` decorator provides shorthand for automatically returning a serialized representation of the task, when your POST request returns. +All Actions will return a serialized representation of the task, when your POST request returns. If the task completes within a default timeout period (usually 1 second) then the completed Task representation will be returned. If the task is still running after this timeout period, the "in-progress" Task representation will be returned. The final output value can then be retrieved at a later time. An example of a long running task may look like: @@ -31,15 +31,13 @@ An example of a long running task may look like: ... from labthings.tasks import taskify - from labthings.server.decorators import marshal_task + from labthings.server.decorators import ThingAction + @ThingAction class SlowAPI(View): - @marshal_task def post(self): - # Run the long-running function as a task - task = taskify(long_running_function)(function_argument_1, function_argument_2) - # Return the task object. Let @marshal_task handle serialization - return task + # Return the task object. + return long_running_function(function_argument_1, function_argument_2) After some time, once the task has completed, it could be retreived using: diff --git a/openflexure_microscope/api/default_extensions/autofocus.py b/openflexure_microscope/api/default_extensions/autofocus.py index 482d9c39..ad9e17b5 100644 --- a/openflexure_microscope/api/default_extensions/autofocus.py +++ b/openflexure_microscope/api/default_extensions/autofocus.py @@ -1,9 +1,9 @@ from labthings.server.find import find_component from labthings.server.extensions import BaseExtension from labthings.server.view import View -from labthings.server.decorators import ThingAction, ThingProperty, marshal_task +from labthings.server.decorators import ThingAction, ThingProperty -from openflexure_microscope.devel import JsonResponse, request, taskify, abort +from openflexure_microscope.devel import JsonResponse, request, abort from openflexure_microscope.utilities import set_properties import time @@ -337,8 +337,6 @@ class AutofocusAPI(View): """ Run a standard autofocus """ - - @marshal_task def post(self): payload = JsonResponse(request) microscope = find_component("org.openflexure.microscope") @@ -351,10 +349,9 @@ class AutofocusAPI(View): if microscope.has_real_stage(): logging.debug("Running autofocus...") - task = taskify(autofocus)(microscope, dz) # return a handle on the autofocus task - return task + return autofocus(microscope, dz) else: abort(503, "No stage connected. Unable to autofocus.") @@ -365,8 +362,6 @@ class FastAutofocusAPI(View): """ Run a fast autofocus """ - - @marshal_task def post(self): payload = JsonResponse(request) microscope = find_component("org.openflexure.microscope") @@ -382,12 +377,11 @@ class FastAutofocusAPI(View): if microscope.has_real_stage(): logging.debug("Running autofocus...") - task = taskify(fast_up_down_up_autofocus)( - microscope, dz=dz, mini_backlash=backlash - ) # return a handle on the autofocus task - return task + return fast_up_down_up_autofocus( + microscope, dz=dz, mini_backlash=backlash + ) else: abort(503, "No stage connected. Unable to autofocus.") diff --git a/openflexure_microscope/api/default_extensions/camera_stage_mapping/extension.py b/openflexure_microscope/api/default_extensions/camera_stage_mapping/extension.py index 6ffe44d0..76732a38 100644 --- a/openflexure_microscope/api/default_extensions/camera_stage_mapping/extension.py +++ b/openflexure_microscope/api/default_extensions/camera_stage_mapping/extension.py @@ -7,14 +7,12 @@ from labthings.server.view import View from labthings.server.find import find_component from labthings.server.extensions import BaseExtension from labthings.server.decorators import ( - marshal_task, ThingAction, use_args, ThingProperty, ) from labthings.server import fields -from labthings.core.tasks import taskify from labthings.core.utilities import get_by_path, set_by_path, create_from_path @@ -146,15 +144,12 @@ class Calibrate1DView(View): @use_args( {"direction": fields.List(fields.Float(), required=True, example=[1, 0, 0])} ) - @marshal_task def post(self, args): """Calibrate one axis of the microscope stage against the camera.""" direction = np.array(args.get("direction")) - task = taskify(csm_extension.calibrate_1d)(direction) - - return task + return csm_extension.calibrate_1d(direction) csm_extension.add_view(Calibrate1DView, "/calibrate_1d", endpoint="calibrate_1d") @@ -162,12 +157,9 @@ csm_extension.add_view(Calibrate1DView, "/calibrate_1d", endpoint="calibrate_1d" @ThingAction class CalibrateXYView(View): - @marshal_task def post(self): """Calibrate both axes of the microscope stage against the camera.""" - task = taskify(csm_extension.calibrate_xy)() - - return task + return csm_extension.calibrate_xy() csm_extension.add_view(CalibrateXYView, "/calibrate_xy", endpoint="calibrate_xy") diff --git a/openflexure_microscope/api/default_extensions/picamera_autocalibrate/extension.py b/openflexure_microscope/api/default_extensions/picamera_autocalibrate/extension.py index ff48ed0b..ac297b3d 100644 --- a/openflexure_microscope/api/default_extensions/picamera_autocalibrate/extension.py +++ b/openflexure_microscope/api/default_extensions/picamera_autocalibrate/extension.py @@ -1,9 +1,7 @@ from labthings.server.view import View from labthings.server.find import find_component from labthings.server.extensions import BaseExtension -from labthings.server.decorators import marshal_task, ThingAction - -from labthings.core.tasks import taskify +from labthings.server.decorators import ThingAction from flask import abort @@ -62,7 +60,6 @@ def recalibrate(microscope): @ThingAction class RecalibrateView(View): - @marshal_task def post(self): microscope = find_component("org.openflexure.microscope") @@ -71,7 +68,7 @@ class RecalibrateView(View): logging.info("Starting microscope recalibration...") - return taskify(recalibrate)(microscope) + return recalibrate(microscope) @ThingAction diff --git a/openflexure_microscope/api/default_extensions/scan.py b/openflexure_microscope/api/default_extensions/scan.py index 9ccc7fb4..f8aac1fb 100644 --- a/openflexure_microscope/api/default_extensions/scan.py +++ b/openflexure_microscope/api/default_extensions/scan.py @@ -8,10 +8,10 @@ from functools import reduce from openflexure_microscope.captures.capture_manager import generate_basename from labthings.server.find import find_component, find_extension from labthings.server.extensions import BaseExtension -from labthings.server.decorators import marshal_task, use_args, ThingAction +from labthings.server.decorators import use_args, ThingAction from labthings.server import fields -from openflexure_microscope.devel import taskify, abort, update_task_progress +from openflexure_microscope.devel import abort, update_task_progress from labthings.server.view import View import time @@ -309,7 +309,6 @@ class TileScanAPI(View): "resize": fields.Dict(missing=None), # TODO: Validate keys } ) - @marshal_task def post(self, args): microscope = find_component("org.openflexure.microscope") @@ -327,7 +326,9 @@ class TileScanAPI(View): abort(404) logging.info("Running tile scan...") - task = taskify(tile)( + + # return a handle on the scan task + return tile( microscope, basename=args.get("filename"), temporary=args.get("temporary"), @@ -343,9 +344,6 @@ class TileScanAPI(View): tags=args.get("tags"), ) - # return a handle on the scan task - return task - scan_extension_v2 = BaseExtension("org.openflexure.scan", version="2.0.0") diff --git a/openflexure_microscope/api/default_extensions/zip_builder.py b/openflexure_microscope/api/default_extensions/zip_builder.py index d0e27c41..5deb2586 100644 --- a/openflexure_microscope/api/default_extensions/zip_builder.py +++ b/openflexure_microscope/api/default_extensions/zip_builder.py @@ -1,7 +1,6 @@ from openflexure_microscope.devel import ( JsonResponse, request, - taskify, update_task_progress, ) @@ -22,7 +21,6 @@ from labthings.server.utilities import description_from_view from labthings.server.decorators import ( ThingAction, ThingProperty, - marshal_task, marshal_with, pre_dump, ) @@ -142,19 +140,16 @@ default_zip_manager = ZipManager() @ThingAction class ZipBuilderAPIView(View): - @marshal_task def post(self): ids = list(JsonResponse(request).json) microscope = find_component("org.openflexure.microscope") - task = taskify(default_zip_manager.marshaled_build_zip_from_capture_ids)( + # Return a handle on the autofocus task + return default_zip_manager.marshaled_build_zip_from_capture_ids( microscope, ids ) - # Return a handle on the autofocus task - return task - @ThingProperty class ZipListAPIView(View): diff --git a/openflexure_microscope/devel/__init__.py b/openflexure_microscope/devel/__init__.py index 519e2ce1..4530dd81 100644 --- a/openflexure_microscope/devel/__init__.py +++ b/openflexure_microscope/devel/__init__.py @@ -12,7 +12,6 @@ from labthings.core.tasks import ( current_task, update_task_progress, update_task_data, - taskify, ) @@ -24,7 +23,6 @@ __all__ = [ "current_task", "update_task_progress", "update_task_data", - "taskify", "abort", "escape", "Response",