def test_task_failure_with_upstream_secrets_doesnt_store_secret_value_and_recompute_if_necessary( client, ): @prefect.task(max_retries=2, retry_delay=timedelta(minutes=100)) def is_p_three(p): if p == 3: raise ValueError("No thank you.") return p with prefect.Flow("test", result=PrefectResult()) as f: p = prefect.tasks.secrets.PrefectSecret("p") res = is_p_three(p) with prefect.context(secrets=dict(p=3)): state = CloudFlowRunner(flow=f).run(return_tasks=[res]) assert state.is_running() assert isinstance(state.result[res], Retrying) assert state.result[res].cached_inputs["p"].location is None ## here we set the result of the secret to an empty result, ensuring ## it will get converted to a "true" result; ## we expect that the upstream value will actually get recomputed from context ## through the SecretResultHandler safe = SecretResult(p) state.result[p] = Success(result=safe) state.result[res].start_time = pendulum.now("utc") state.result[res].cached_inputs = dict(p=safe) with prefect.context(secrets=dict(p=4)): new_state = CloudFlowRunner(flow=f).run(return_tasks=[res], task_states=state.result) assert new_state.is_successful() assert new_state.result[res].result == 4
def test_simple_three_task_flow_with_first_task_retrying(monkeypatch, executor): """ If the first task retries, then the next two tasks shouldn't even make calls to Cloud because they won't pass their upstream checks """ @prefect.task(max_retries=1, retry_delay=datetime.timedelta(minutes=20)) def error(): 1 / 0 flow_run_id = str(uuid.uuid4()) task_run_id_1 = str(uuid.uuid4()) task_run_id_2 = str(uuid.uuid4()) task_run_id_3 = str(uuid.uuid4()) with prefect.Flow(name="test") as flow: t1 = error() t2 = prefect.Task() t3 = prefect.Task() t2.set_upstream(t1) t3.set_upstream(t2) client = MockedCloudClient( flow_runs=[FlowRun(id=flow_run_id)], task_runs=[ TaskRun( id=task_run_id_1, task_slug=flow.slugs[t1], flow_run_id=flow_run_id ), TaskRun( id=task_run_id_2, task_slug=flow.slugs[t2], flow_run_id=flow_run_id ), TaskRun( id=task_run_id_3, task_slug=flow.slugs[t3], flow_run_id=flow_run_id ), ], monkeypatch=monkeypatch, ) with prefect.context(flow_run_id=flow_run_id): state = CloudFlowRunner(flow=flow).run( return_tasks=flow.tasks, executor=executor ) assert state.is_running() assert client.flow_runs[flow_run_id].state.is_running() assert isinstance(client.task_runs[task_run_id_1].state, Retrying) assert client.task_runs[task_run_id_1].version == 3 assert client.task_runs[task_run_id_2].state.is_pending() assert client.task_runs[task_run_id_2].version == 0 assert client.task_runs[task_run_id_3].state.is_pending() assert client.task_runs[task_run_id_2].version == 0 assert client.call_count["set_task_run_state"] == 3
def test_flow_runner_raises_endrun_if_client_cant_update_state(monkeypatch): flow = prefect.Flow(name="test") get_flow_run_info = MagicMock(return_value=MagicMock(state=None)) set_flow_run_state = MagicMock(side_effect=SyntaxError) client = MagicMock(get_flow_run_info=get_flow_run_info, set_flow_run_state=set_flow_run_state) monkeypatch.setattr("prefect.engine.cloud.flow_runner.Client", MagicMock(return_value=client)) ## if ENDRUN is raised, res will be last state seen res = CloudFlowRunner(flow=flow).run() assert set_flow_run_state.called assert res.is_running()
def test_task_failure_caches_inputs_automatically(client): @prefect.task(max_retries=2, retry_delay=timedelta(seconds=100)) def is_p_three(p): if p == 3: raise ValueError("No thank you.") with prefect.Flow("test") as f: p = prefect.Parameter("p") res = is_p_three(p) state = CloudFlowRunner(flow=f).run(return_tasks=[res], parameters=dict(p=3)) assert state.is_running() assert isinstance(state.result[res], Retrying) assert state.result[res].cached_inputs["p"].location == "3" last_state = client.set_task_run_state.call_args_list[-1][-1]["state"] assert isinstance(last_state, Retrying) assert last_state.cached_inputs["p"].location == "3"
def test_task_failure_caches_constant_inputs_automatically(client): @prefect.task(max_retries=2, retry_delay=timedelta(seconds=100)) def is_p_three(p): if p == 3: raise ValueError("No thank you.") with prefect.Flow("test") as f: res = is_p_three(3) state = CloudFlowRunner(flow=f).run(return_tasks=[res]) assert state.is_running() assert isinstance(state.result[res], Retrying) exp_res = Result(3, result_handler=ConstantResultHandler(3)) assert not state.result[res].cached_inputs["p"] == exp_res exp_res.store_safe_value() assert state.result[res].cached_inputs["p"] == exp_res last_state = client.set_task_run_state.call_args_list[-1][-1]["state"] assert isinstance(last_state, Retrying) assert last_state.cached_inputs["p"] == exp_res
def test_simple_two_task_flow_with_final_task_already_running( monkeypatch, executor): flow_run_id = str(uuid.uuid4()) task_run_id_1 = str(uuid.uuid4()) task_run_id_2 = str(uuid.uuid4()) with prefect.Flow(name="test") as flow: t1 = prefect.Task() t2 = prefect.Task() t2.set_upstream(t1) client = MockedCloudClient( flow_runs=[FlowRun(id=flow_run_id)], task_runs=[ TaskRun(id=task_run_id_1, task_slug=flow.slugs[t1], flow_run_id=flow_run_id), TaskRun( id=task_run_id_2, task_slug=flow.slugs[t2], version=1, flow_run_id=flow_run_id, state=Running(), ), ], monkeypatch=monkeypatch, ) with prefect.context(flow_run_id=flow_run_id): state = CloudFlowRunner(flow=flow).run(return_tasks=flow.tasks, executor=executor) assert state.is_running() assert client.flow_runs[flow_run_id].state.is_running() assert client.task_runs[task_run_id_1].state.is_successful() assert client.task_runs[task_run_id_1].version == 2 assert client.task_runs[task_run_id_2].state.is_running() assert client.task_runs[task_run_id_2].version == 1