Repository: PrefectHQ/prefect

Issue:
Signals not being captured correctly for LocalDaskExecutor
## Archived from the [Prefect Public Slack Community](https://prefect.io/slack)

**bastian.roehrig**: Hi everyone, I found a weird behaviour when I use a timeout with a LocalDaskExecutor and manually raise a Success. The task will always fail with the timeout error message, even if it takes less time than the specified timeout. Minimal example:


```
from prefect import Flow, task
from prefect.executors import LocalDaskExecutor

from prefect.engine.signals import SUCCESS


@task(timeout=60)
def succeed():
    raise SUCCESS()


with Flow("timeout-test") as flow:
    succeed()

flow.executor = LocalDaskExecutor()
flow.register(project_name="tutorial")
```

Is this the intended behaviour? Can anyone reproduce it?

**zach555**: Hi <@U02BG7QTYGM>, thanks for the minimal example here! I can reproduce. I don't believe this is the intended behavior, I'll check with the team.

**zach555**: <@ULVA73B9P> archive "Signals not being captured correctly for LocalDaskExecutor"

Original thread can be found [here](https://prefect-community.slack.com/archives/CL09KU1K7/p1630392939250300?thread_ts=1630392939.250300&cid=CL09KU1K7).




Discussion:

Resolving patch:
diff --git a/src/prefect/utilities/executors.py b/src/prefect/utilities/executors.py
--- a/src/prefect/utilities/executors.py
+++ b/src/prefect/utilities/executors.py
@@ -20,7 +20,7 @@
 from prefect import config
 from prefect.client import Client
 from prefect.configuration import to_environment_variables
-from prefect.exceptions import TaskTimeoutSignal
+from prefect.exceptions import TaskTimeoutSignal, PrefectSignal
 from prefect.utilities.logging import get_logger
 from typing import (
     TYPE_CHECKING,
@@ -297,6 +297,15 @@ def multiprocessing_safe_run_and_retrieve(
             logger.debug(f"{name}: Executing...")
             return_val = fn(*args, **kwargs)
             logger.debug(f"{name}: Execution successful.")
+    except PrefectSignal as exc:
+        # We need to ensure PrefectSignals are captured and put in the
+        # queue correctly, otherwise no value is returned and
+        # the task runner assumes execution has timed out
+        return_val = exc
+        logger.error(
+            f"{name}: Encountered a PrefectSignal {type(exc).__name__}, "
+            f"returning details as a result..."
+        )
     except Exception as exc:
         return_val = exc
         logger.error(


Test patch:
diff --git a/tests/executors/test_executors.py b/tests/executors/test_executors.py
--- a/tests/executors/test_executors.py
+++ b/tests/executors/test_executors.py
@@ -18,6 +18,7 @@
     LocalDaskExecutor,
     LocalExecutor,
 )
+from prefect.engine.signals import SUCCESS
 
 
 @pytest.mark.parametrize(
@@ -212,6 +213,19 @@ def long_task():
         # Windows which tends to be a little slower
         assert (stop - start) < (6 if sys.platform == "win32" else 4)
 
+    def test_captures_prefect_signals(self):
+        e = LocalDaskExecutor()
+
+        @prefect.task(timeout=1)
+        def succeed():
+            raise SUCCESS()
+
+        with prefect.Flow("signal-test", executor=e) as flow:
+            succeed()
+
+        res = flow.run()
+        assert res.is_successful()
+
 
 class TestLocalExecutor:
     def test_submit(self):