Skip to content

Commit

Permalink
feat(arcor2_runtime): provide on pause and on resume callbacks
Browse files Browse the repository at this point in the history
  • Loading branch information
Jiri Zajic committed Aug 2, 2024
1 parent a441018 commit 8f2857b
Showing 1 changed file with 90 additions and 0 deletions.
90 changes: 90 additions & 0 deletions src/python/arcor2_runtime/action.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,79 @@ class Globals:

lock: threading.Lock = field(default_factory=threading.Lock)

disable_action_wrapper: bool = False


g = Globals()


class PackageStateHandler(object):
"""Singleton class that manages callbacks for PAUSE and RESUME events."""

_instance = None
_on_pause_callbacks: list[Callable[...,None]] = []
_on_resume_callbacks: list[Callable[...,None]] = []
_instance_lock = threading.Lock()
_execution_lock = threading.Lock()

def __init__(self):
"""Forbidden initializer."""
raise RuntimeError("Call get_instance() instead")

@classmethod
def get_instance(cls):
"""Returns the singleton instance of the class."""
if cls._instance is None:
with cls._instance_lock:
if cls._instance is None:
cls._instance = cls.__new__(cls)
return cls._instance

def add_on_pause_callback(self, on_pause_callback: Callable[...,None]):
"""Adds a callback to be executed when the script is paused."""
self._on_pause_callbacks.append(on_pause_callback)

def remove_on_pause_callback(self, on_pause_callback: Callable[...,None]):
"""Removes a callback to be executed when the script is paused."""
self._on_pause_callbacks.remove(on_pause_callback)

def add_on_resume_callback(self, on_resume_callback: Callable[...,None]):
"""Adds a callback to be executed when the script is resumed."""
self._on_resume_callbacks.append(on_resume_callback)

def remove_on_resume_callback(self, on_resume_callback: Callable[...,None]):
"""Removes a callback to be executed when the script is resumed."""
self._on_resume_callbacks.remove(on_resume_callback)

def execute_on_pause(self):
"""Executes all pause callbacks."""

with self._execution_lock:
# Disable action wrapper to prevent stack overflow when action is called from PAUSE callback.
g.disable_action_wrapper = True

try:
for callback in self._on_pause_callbacks:
callback()
finally:
# Enable action wrapper back.
g.disable_action_wrapper = False

def execute_on_resume(self):
"""Executes all resume callbacks."""

with self._execution_lock:
# Disable action wrapper to prevent stack overflow when action is called from RESUME callback.
g.disable_action_wrapper = True

try:
for callback in self._on_resume_callbacks:
callback()
finally:
# Enable action wrapper back.
g.disable_action_wrapper = False


def patch_aps(project: CachedProject) -> None:
"""orientations / joints have to be monkey-patched with AP's ID in order to
make breakpoints work in @action."""
Expand Down Expand Up @@ -162,11 +231,18 @@ def handle_stdin_commands(*, before: bool, breakpoint: bool = False) -> None:
g.pause_on_next_action.clear()
g.resume.clear()
g.pause.set()

# Execute on pause callbacks, prevent transfer to PAUSED state if callback causes exception.
PackageStateHandler.get_instance().execute_on_pause()

print_event(PackageState(PackageState.Data(PackageState.Data.StateEnum.PAUSED)))

if g.pause.is_set():
g.resume.wait()

# Execute on resume callbacks, if callback causes exception, it is in RUNNING state.
PackageStateHandler.get_instance().execute_on_resume()


F = TypeVar("F", bound=Callable[..., Any])

Expand Down Expand Up @@ -215,6 +291,20 @@ def wrapper(obj: Generic, *action_args: Any, an: None | str = None, **kwargs: An
if thread_id not in g.depth:
g.depth[thread_id] = 0

# Execute action without wrapping in case that action wrapper is disabled.
if g.disable_action_wrapper:
g.depth[thread_id] += 1

try:
res = f(obj, *action_args, an=an, **kwargs)
except Arcor2Exception:
g.depth[thread_id] = 0
g.ea[thread_id] = None
raise

g.depth[thread_id] -= 1
return res

try:
action_id: None | str = None
action_mapping_provided = hasattr(obj, ACTION_NAME_ID_MAPPING_ATTR)
Expand Down

0 comments on commit 8f2857b

Please sign in to comment.