-
Notifications
You must be signed in to change notification settings - Fork 118
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Set RedisModel.Meta.database
at runtime, not import time
#519
Comments
It seems that the problem you described causes this issue: #527 |
Thanks. Your solution works for me. I am using now: @classmethod
def db(cls):
if not cls._meta.database:
cls._meta.database = get_redis_connection(url=db_url)
return super().db() Update: It does not work. It just seemed to work on my notebook, as Redis is running there at This happens, because I wanted to use class RedisUser(JsonModel):
fields...
_conn: Optional[Redis] = None
@classmethod
def db(cls):
if not cls._conn:
cls._conn = get_redis_connection(url=db_url)
cls._meta.database = cls._conn
return super().db() |
You can set the and then use it in the Meta class of your model.
By default, not supplying the REDIS_OM_URL and not setting the database, will fallback to 6379 and localhost. That is where it has the connection string from. Of course, your workaround works too. However, the point you are making is still valid. It should not try to connect before one needs the connection. There should be a lazy connection by default and eager as an option one needs to set deliberately. If redis is not available, the application will die during the import of all the models. I suggest this requires an architectural and code change. |
@svabra That is not what's happening.
>>> from myapp import RedisUser
>>> RedisUser.Meta.database = get_redis_connection(url="redis://10.20.30.40:6379")
>>> RedisUser._meta.database = get_redis_connection(url="redis://10.20.30.40:6379")
>>> RedisUser.find().first()
redis.exceptions.ConnectionError: Error 111 connecting to 127.0.0.1:6379. Connection refused. The |
@dansan Well, it is clearly attempting to open when importing a JsonModel in one's code. It requires no instantiation to that. As you pointed out, it becomes significantly quirkier to tested. Or what do you mean by it is lazy "opening"? I ask differently: has anyone written a test that proves it is NOT attempting to connect while importing? I gladly see the results to that. Thanks for sharing. (Yes, I do understand that the connection does not seem to be modifiable after being set once. Another issue.). Also, I really would love to hear the reasoning of the author of that. There must have been a reason to tightly-couple model and connection/server. |
It's an experimental library. The reason might be that, getting the library to work was of higher importance than getting all the nitty gritty details right. Lazy connections seem like a better option. Hopefully this will be considered in future updates. |
I added a PR that implements lazy DB connection configuration: When def my_connection():
return Redis(**get_db_config())
class RedisUser(JsonModel):
fields...
class Meta:
database = my_connection
I added a few tests. They might be in the wrong file or their style is not how you would do it. Feel free to fix it. The PR is meant as a start to find a solution. It's probably not perfect at all :) |
Did the discussion go anywhere? It has been over a year and async support is more-or-less still broken because of this. |
Been bugging me for days. Hopefully get fixed soon. |
Often the software I write does not know the configuration at import time. It has to load it from multiple sources, as it is executed in different environments and with different (CLI) options.
Generally, It's best practice to not open database or network connections (or do any I/O) at import time.
Having to set the database connection at import time also makes testing harder. Things have to be patched before importing any dependency that might import the module with the
RedisModel
.It would be more convenient if the database connection could be set at runtime... e.g.
MyModel.Meta.database = ...
when my software has finished collecting the configuration and other setup steps.This does currently not work, because the creation of the class through the metaclass stores the value somewhere I cannot change it later.
Alternatively (and maybe less work to implement with the current code - not that I have looked at it) would be to allow the value of
RedisModel.Meta.database
to be a callable (typeCallable[[], Redis]
). That could be provided at import time without having to know the database connection yet, and would not even need patching in tests (as the test can just create a testing configuration) - it's dependency injection.The built-in
callable()
can be used to test, if the value inMyModel.Meta.database
is a callable. Luckily aRedis
connection pool object is not a callable.The text was updated successfully, but these errors were encountered: