Repository: PrefectHQ/prefect

Issue:
When a flow has no storage attached, the agent should mark the run as failed

It appears that if the Agent picks up a run with no storage, it will mark it as submitted. This run will then exist in limbo forever, as it can never be run. The agent should put it in a failed state if it can recognize it'll never run.


Discussion:

Resolving patch:
diff --git a/src/prefect/agent/local/agent.py b/src/prefect/agent/local/agent.py
--- a/src/prefect/agent/local/agent.py
+++ b/src/prefect/agent/local/agent.py
@@ -5,6 +5,7 @@
 
 from prefect import config, context
 from prefect.agent import Agent
+from prefect.engine.state import Failed
 from prefect.environments.storage import Docker
 from prefect.serialization.storage import StorageSchema
 from prefect.utilities.graphql import GraphQLResult
@@ -78,9 +79,14 @@ def deploy_flows(self, flow_runs: list) -> None:
 
             storage = StorageSchema().load(flow_run.flow.storage)
             if not isinstance(StorageSchema().load(flow_run.flow.storage), Docker):
-                self.logger.error(
-                    "Storage for flow run {} is not of type Docker.".format(flow_run.id)
+                msg = "Storage for flow run {} is not of type Docker.".format(
+                    flow_run.id
                 )
+                state_msg = "Agent {} failed to run flow: ".format(self.name) + msg
+                self.client.set_flow_run_state(
+                    flow_run.id, version=flow_run.version, state=Failed(state_msg)
+                )
+                self.logger.error(msg)
                 continue
 
             env_vars = self.populate_env_vars(flow_run=flow_run)
@@ -97,7 +103,15 @@ def deploy_flows(self, flow_runs: list) -> None:
                         "Successfully pulled image {}...".format(storage.name)
                     )
                 except docker.errors.APIError as exc:
-                    self.logger.error("Issue pulling image {}".format(storage.name))
+                    msg = "Issue pulling image {}".format(storage.name)
+                    state_msg = (
+                        "Agent {} failed to pull image for flow: ".format(self.name)
+                        + msg
+                    )
+                    self.client.set_flow_run_state(
+                        flow_run.id, version=flow_run.version, state=Failed(msg)
+                    )
+                    self.logger.error(msg)
 
             # Create a container
             self.logger.debug("Creating Docker container {}".format(storage.name))


Test patch:
diff --git a/tests/agent/test_local_agent.py b/tests/agent/test_local_agent.py
--- a/tests/agent/test_local_agent.py
+++ b/tests/agent/test_local_agent.py
@@ -189,6 +189,7 @@ def test_local_agent_deploy_flows(monkeypatch, runner_token):
 
 def test_local_agent_deploy_flows_storage_continues(monkeypatch, runner_token):
 
+    monkeypatch.setattr("prefect.agent.agent.Client", MagicMock())
     api = MagicMock()
     api.ping.return_value = True
     api.create_container.return_value = {"Id": "container_id"}
@@ -200,7 +201,11 @@ def test_local_agent_deploy_flows_storage_continues(monkeypatch, runner_token):
     agent.deploy_flows(
         flow_runs=[
             GraphQLResult(
-                {"flow": GraphQLResult({"storage": Local().serialize()}), "id": "id"}
+                {
+                    "flow": GraphQLResult({"storage": Local().serialize()}),
+                    "id": "id",
+                    "version": "version",
+                }
             )
         ]
     )