Hi, I have a question that is a follow-up from one...
# ask-community
d
Hi, I have a question that is a follow-up from one question I asked on April 19th. I managed to deploy a prefect server and to run flows with docker storage and a DaskKubernetes environment. The only hurdle I have left (I hope!) is that an important part of our Task depend on some common configuration set on
prefect.context
. This includes some secrets and some URLs and object ids on some internal rest services. Before we used the prefect server, we had a small cli that would populate the
prefect.context
and use it when running the flow:
Copy code
with prefect.context(**our_custom_vars):
    flow_state = flow.run(parameters=flow_parameters, ...)
My ultimate objective is to have a flow with a default context that I can run from the UI or schedule it with that context when deploying it. In my question of April 19th, @Jeremiah pointed out that there is no way to set these contexts at the moment and you will discuss it internally later… is there any update on this front? Otherwise, I am looking for alternatives or workarounds: One workaround would be to understand where the context would be set on an agent, worker, or runner (I am not sure which one). Jeremiah also pointed our that the FlowRunner requests the context from the server, but I can’t find where or even if a flow has its context saved anywhere (there does not seem to be a field named context on the
flow_by_pk
query). Another workaround would be to populate environment variables or change the default
config.toml
of the agent, worker, or runner (I am not sure which one) so that the
prefect.context
is populated with these values. I am not sure if this would work. Another workaround may be to override the
__setstate__
and
__getstate__
method, so that the flow can retrieve the context when unpickled. I am not sure if this would work either. Any ideas on which of these workarounds may be the best bet here?
j
Hey David, first up I have a quick workaround for you which is a more flexible version of your second idea. (And I apologize, I totally forgot we support what I’m about to describe or I would have mentioned it sooner). You can do exactly what you want via env var:
Copy code
$ PREFECT__CONTEXT__CUSTOM__VALUE=5 python -c "import prefect; print(prefect.context['custom']['value'])"

5
As long as the env var starts with
PREFECT__CONTEXT
it will be parsed into your config and from there into context (including any nesting you indicate with other
__
separators, and a best effort to parse ints, floats, and bools
d
No need to apologize Jeremiah, you are all already doing a great job…
j
For a more “first class” approach at this, we are exploring introducing runtime callables to allow flows (and clocks!) to declare default contexts and environments, similar to how clocks can declare parameter defaults today.
One creative tension we have, though, is that we actually don’t want to encourage context as a means of passing user-supplied data, because if people begin to rely on it over, for example, parameters without really understanding that it’s not a mutable object once the flow starts, it can introduce some unpleasant bugs
So in addition to what I wrote, we’re also trying to better explain when you should and shouldn’t use context to avoid abuse. For clarity, I think the use case you’re describing (making env vars transaprently available) is a good one, but requires an upfront config that we medium support right now. So in sum, no hard update on how we will expose this but it’s something we’ve discussed and are thinking about it.
d
Well, we do agree and we are not using context as a mutable object, I’ll tell you later our use cases though…
But back to the workaround: Where would you set these env variable ? I tried to set it on the agent, and I have a simple task that prints the context; I could not find the variable that way…
j
Hm, I think I may have to tag @josh in to help with setting env vars from the agent
d
My agent is a copy/paste of your src/prefect/agent/kubernetes/deployment.yaml with the following change:
Copy code
env:
   ...
   - name: PREFECT__CONTEXT__FOO
     value: 'fofofofofofofofof'
j
Agents accept a dictionary of environment variables at runtime:
Copy code
- env_vars (dict, optional): a dictionary of environment variables and values that will be set on each flow run that this agent submits for execution
However I don’t think that would satisfy the use case of an installed agent being able to set env vars on all runs. This would be a great enhancement 🙂
d
Ok let met try that. In my case, fortunately, I can live with the same context for the sole agent that we have.
j
In the meantime as a workaround you could edit your agent deployment yaml command to add the environment variables:
Copy code
args: ["prefect agent start kubernetes"]
to
Copy code
args: ["prefect agent start kubernetes -e MY_VAR=test -e MY_VAR2=test2"]
d
Ok thanks for the info Josh. I tried a deployment with
args: ["prefect agent start -v kubernetes -e PREFECT__CONTEXT__FOO=bar123"
and I can see that the k8s job does have this as a environment variable when I do
kubectl describe job …
Copy code
...
    Environment:
      PREFECT__CLOUD__API:                          <http://apollo:4200>
      PREFECT__CLOUD__AUTH_TOKEN:
      PREFECT__CONTEXT__FLOW_RUN_ID:                98c1491c-d0dc-4885-90df-f84cb702d36b
      PREFECT__CONTEXT__NAMESPACE:                  default
      PREFECT__CLOUD__AGENT__LABELS:                []
      PREFECT__LOGGING__LOG_TO_CLOUD:               true
      PREFECT__CLOUD__USE_LOCAL_SECRETS:            false
      PREFECT__LOGGING__LEVEL:                      DEBUG
      PREFECT__ENGINE__FLOW_RUNNER__DEFAULT_CLASS:  prefect.engine.cloud.CloudFlowRunner
      PREFECT__ENGINE__TASK_RUNNER__DEFAULT_CLASS:  prefect.engine.cloud.CloudTaskRunner
      PREFECT__CONTEXT__FOO:                        bar123
...
However, the dask pods do not inherit these environment variables, so the context is still missing the
foo
variable
I feel a bit stupid; I found a much much easier approach: Just fill the
/root/.prefect/config.toml
on the
Docker
storage for my flow
This way, I can have flow-specific contexts
j
Haha the lowest tech approach always wins