-
Notifications
You must be signed in to change notification settings - Fork 6
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
Allow runtime settings overrides #70
Conversation
Co-authored-by: Peter Law <[email protected]>
Co-authored-by: Peter Law <[email protected]>
Introduce an long-name adapter which facades away the name munging logic and allows re-use of this both for Django settings and custom settings. This simplifies AppSettings which can now focus on just layering the settings. While this doesn't gain any type checking on the settings from the layers, that was never present anyway.
The previous approach of reloading the settings module worked ok when the module itself was what was imported & mutated, however with the move to a layered approach that's no longer the case.
442a4d7
to
154b929
Compare
This slightly changes the behaviour of the mock_workers helpers, however the default is an empty dictionary so this feels like a reasonable trade-off for using the more standard override_settings util.
154b929
to
31eb204
Compare
16b78f0
to
5f5acbe
Compare
|
||
# Allow per-queue overrides of the backend. | ||
BACKEND_OVERRIDES = setting('BACKEND_OVERRIDES', {}) # type: Mapping[QueueName, str] | ||
class AppSettings: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Given this is all internal, should't this inherit from Settings
? This would avoid having to use cast
in django_lightweight_queue/utils.py
.
I could see some concern about having the app_settings
value being more explicitly mutable by adding layers, but it already is in practice (even if the typing says no) so probably not a concern here? If it is I reckon AppSettings
could be made immutable and adding a layer just returns a new instance instead of doing interior mutability.
Scratch that the point in utils is to mutate the global settings so yeah I think making this an explicit part of the API is probably better.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sorry it's taken a while to get back to this. Are you suggesting that add_layer
should be part of the public interface? I had avoided doing that since the consequences of calling it arbitrarily aren't well defined. That said, this is meant to be internal to this package anyway, so maybe it's ok? I'll do that and add a comment clarifying that this file is internal API.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
django_lightweight_queue/utils.py
Outdated
for name in override_names: | ||
short_name = name[len(constants.SETTING_NAME_PREFIX):] | ||
setattr(app_settings, short_name, getattr(extra_settings, name)) | ||
cast(AppSettings, app_settings).add_layer(LongNameAdapter(extra_settings)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
See comment in app_settings.py
- I reckon we can make this work more cleanly without a cast
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This feels unlikely to be a huge problem but one idea to make this safe:
The caveat is that for when someone really wants to do this then we're back to |
So the issue here really is that calls to It's not that changes could be made and that might break things, but rather that changes could be made and we have no reasonable way to detect them and update the system to reflect them. This was already a problem (e.g: the I don't feel I understand how adding contextvars or freezing the settings would help here? |
This avoids needing to cast the settings by instead documenting the expected bounds of the API offered.
Summary
This builds on #62 to introduce support for Django settings being overridden at runtime. While true changes to settings at runtime are not supported, this aims to simplify testing (
django.test.override_settings
should now work) and allow for settings architectures which do not pin down settings values immediately.Consumers must ensure that settings do not change once the system has started however as this could lead to unpredictable behaviours in response. (For example it is possible that queues could have incorrect numbers of workers assigned)
I've rebased this on top of #66 so the tests that introduces help validate that extra-config loading works as expected and updated those tests to work with this new approach.
Code review
I suggest starting with the changes to
app_settings.py
, then looking atutils.py
andtest_extra_config.py
.The remainder of the changes are small adaptations to account for the slightly changed internal API and moving tests to use
override_settings
now that works.