Hello everybody. Prefect showed a very strange beh...
# ask-community
m
Hello everybody. Prefect showed a very strange behavior today, which was not before. In many Flow I have type options as
Copy code
start_date = Parameter("start_date", default=pendulum.now("Europe/Kiev").add(days=-1).to_date_string())
start_date = Parameter("start_date", default=(date.today() - timedelta(1)).strftime("%Y-%m-%d"))
and usually everything worked as needed, ie during the execution of the script the value of the parameter was calculated. However, I noticed that on Saturday, Sunday and Monday (today) all similar parameters were passed as 
2021-10-14
, ie as if Flow was launched on Friday. Last weekend this was not the case (as in general before)
flow run with parameters
a
Hi @Marko Herkaliuk, the first thing I would check is whether you use a Script-based or a Pickle based storage. Which type of storage do you use in general? By default, many storage classes pickle your flow by default, so that the default parameter value is frozen at registration time. But if you use a script-based storage, this will be evaluated at runtime resulting in a behavior that you expect.
m
but in Schedules config parameters is off
hi @Anna Geller. We use Git storage
a
@Marko Herkaliuk I think the best solution is to rewrite the flow so that your default parameter value is None. Then, if parameter value is None, you are dynamically generating default start_date and end_date from a task. And if parameter is not None (e.g. custom run from UI when you do something like backfill), you use a custom parameter. Here is example code that shows what I mean:
Copy code
from prefect import Flow, Parameter, task
import pendulum


@task(log_stdout=True)
def hello_world(user_input: str):
    if user_input is None:
        default_val = pendulum.now("Europe/Kiev").add(days=-1).to_date_string()
        print(f"Hello {default_val}")
    else:
        print(f"hello {user_input}")


with Flow("test-flow") as flow:
    param = Parameter("user_input", default=None)
    hw = hello_world(param)

if __name__ == '__main__':
    flow.run()
    # flow.run(parameters=dict(user_input="2021-10-17"))
m
@Anna Geller thanks, I know about this solution, but everything was working during few last months.
maybe there were some changes in the scheduler that he passed there parameters?
a
nothing I’m aware of. I could ask the team. I would still recommend making parameters static and set the dynamic default from within a task - it seems more robust 🙂
what Prefect version do you use so that I can cross check if there were any changes to Parameter logic?
Also, could you elaborate on what do you mean that in Schedules config parameters is off? What did you modify from the UI as compared to what was defined in your flow?
m
Copy code
prefect:0.15.6-python3.8
We create a schedule through UI, when you do that you can set parameters, but we didn’t do that. That’s what I meant. About wrapper for the parameters - probably we make this.
👍 1
k
Hey @Marko Herkaliuk, you are right we indeed had a change that seems to have affect it. The PR is here , the issue was that runtime parameters were not being sent to the GraphQL API. We’re looking into this.
m
Thnx @Kevin Kho, I am already wrapped date-based parameters, but I will waiting the news about this issue.
👍 1
k
Hey @Marko Herkaliuk, just chatted with the team and that PR will stay because the dynamic parameter was not done by explicit design. Design-wise it’s bad that the script-based storage and pickle-based storage diverge here. This changes the previous behavior, but the current behavior is not considered a bug. Also, Orion will handle dynamic defaults natively and independently of storage so we will head in that direction.
upvote 1
The best practice will be to return the default in a task or function.
m
thank you for information 🖖
👍 1
m
Hey guys, any development here? I faced the exact same problem after upgrade from
0.15.5
to
0.15.9
My flows’ default values were dependent on
schedule
object and were working ok until this. Now they have values from the registration. We use
module
storage
a
@Marko Jamedzija you would need to rewrite your task so that the dynamic default Parameter value is generated from a task rather than from a Parameter. Parameter defaults were never intended to be dynamically evaluated from a flow definition, but rather they should be treated as static default values that can be optionally overridden at runtime. As Kevin said 5 answers above your message, the PR stays and is not getting reverted. If you need help in rewriting the task to use value from a task, LMK, we can help for sure.
m
Thanks for the answer @Anna Geller 🙂 No worries, I’m already doing the updates. I just wanted to know what’s the plan for the future, but I got it now. Thanks!
🙌 1
Actually, I have one question. My previous default values were dependent on
schedule
. So it was like this:
Copy code
run_datetime_hour = (schedule.next(1)[0] - timedelta(hours=2)).strftime("%Y-%m-%dT%H:00:00")

source_start_datetime = Parameter(name="source_start_datetime", default=run_datetime_hour)
Now with this change it will be like this:
Copy code
@task
def get_run_date_time_hour(param_input: str, schedule: Schedule) -> str:
    """
    Returns the previous hour using the schedule if the param_input is not None.
    """
    if param_input:
        return param_input
    elif schedule:
        return (schedule.next(1)[0] - timedelta(hours=2)).strftime("%Y-%m-%dT%H:00:00")
    else:
        raise Exception("Schedule is needed to generate the default value!")

source_start_datetime_param = Parameter(name="source_start_datetime", default=None)
source_start_datetime = get_run_date_time_hour(param_input=source_start_datetime_param, schedule=schedule)
I tested it out locally and it works. Do you think it will work when deployed on prefect server as well, @Anna Geller? Thanks!
a
Instead of taking
schedule.next(1)[0]
, I think it may be better to retrieve this information from the context:
Copy code
import prefect
prefect.context["scheduled_start_time"]
This way, you don’t rely on the schedule object that is valid only at registration time, but instead you leverage the runtime specific value of the
scheduled_start_time
.
m
Great, thanks! I’ll try this out 🙂
I just tried this out, works perfectly! Thanks again @Anna Geller!
🙌 1