Félix Tremblay
04/23/2023, 5:15 AM"Since ConfigurableResource is a dataclass meant to encapsulate config, it is not a good fit for managing state. The recommended pattern in this case is to build a separate class which manages the state of the resource which is provided by the ConfigurableResource class."
To begin with, it's not clear how the proposed pattern is more stateful than just using a ConfigurableResource alone? I'm guessing that in both cases, the class(es) (and their "state") are preserved during the duration of the run? For multiprocess executors there might be a nuance, like the one described in the Legacy Resource guide, but the new concept page does not give explanation.
Moreover, the example shows that the second class is used to initialize the resource (i.e., the api_token is fetched and stored in the init method of the second class). For any special initialization of the resource, I don't think the proposed pattern is necessary. I would prefer to keep only one class and use (i.e., override) its init method like so
def __init__(self, **kwargs):
super().__init__(**kwargs)
self._api_token = ...
It's a common pattern with Pydantic models. I'm interested to know the reasons behind the different approach you are proposing. Unfortunately from the docs alone, there's not really an explanation.
The section about stateful Resources does not make a lot of sense to me. I think that further clarifications and explanations would be beneficial. Thank you! 😃Daniel Vetter
04/23/2023, 11:52 AMCustom __init__ overrides won't be called. This should be replaced with a @root_validator.
https://docs.pydantic.dev/blog/pydantic-v2-alpha/Andras Somi
04/24/2023, 6:56 AMPrivateAttr
from Pydantic for storing some internal state, eg. session for a resource that wraps an API:
from pydantic import PrivateAttr
from dagster import ConfigurableResource
import requests
class MyResource(ConfigurableResource):
_session: requests.Session | None = PrivateAttr(None)
@property
def session(self):
if self._session is None:
self._session = requests.Session()
# add headers and default parameters to session, etc.
return self._session
def query(self, url, params):
self.session.get(url, params=params)
__enter__
and __exit__
methods to the resource, it worked for me in several cases (for the previous example, you can create your session in __enter__
and tear it down in __exit__
).Félix Tremblay
04/24/2023, 5:49 PMenter
and exit
methods for the ConfigurableResource, does Dagster automatically call these methods for you, or do you have to use the with
yourself in your op/asset?chris
04/24/2023, 8:20 PMben
04/24/2023, 9:11 PM@op
def my_op(my_context_resource: MyContextResource):
with my_context_resource.open():
pass
Second, on managing state in a ConfigurableResource
. We initially shipped a constrained API with the aim of clearly separating the resource config schema and stateful implementation, with the knowledge that we could relax this constraint later on. Based on feedback, for many users this seems like a heavy-handed prescription and is something we’re re-examining. In particular, we are considering support for an initialization method which would allow users to set private fields on a resource directly.Félix Tremblay
04/24/2023, 9:47 PMben
04/27/2023, 8:13 PMFélix Tremblay
05/06/2023, 1:34 AM