-
Notifications
You must be signed in to change notification settings - Fork 3.5k
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
heavily optimize the write speed of the callback receiver #5618
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
@@ -28,6 +28,8 @@ | |||||||||||||||||||
from awx.conf.models import Setting | ||||||||||||||||||||
from awx.conf.migrations._reencrypt import decrypt_field as old_decrypt_field | ||||||||||||||||||||
|
||||||||||||||||||||
import cachetools | ||||||||||||||||||||
|
||||||||||||||||||||
# FIXME: Gracefully handle when settings are accessed before the database is | ||||||||||||||||||||
# ready (or during migrations). | ||||||||||||||||||||
|
||||||||||||||||||||
|
@@ -136,6 +138,14 @@ def filter_sensitive(registry, key, value): | |||||||||||||||||||
return value | ||||||||||||||||||||
|
||||||||||||||||||||
|
||||||||||||||||||||
# settings.__getattr__ is called *constantly*, and the LOG_AGGREGATOR_ ones are | ||||||||||||||||||||
# so ubiquitous when external logging is enabled that they should kept in memory | ||||||||||||||||||||
# with a short TTL to avoid even having to contact memcached | ||||||||||||||||||||
# the primary use case for this optimization is the callback receiver | ||||||||||||||||||||
# when external logging is enabled | ||||||||||||||||||||
LOGGING_SETTINGS_CACHE = cachetools.TTLCache(maxsize=50, ttl=1) | ||||||||||||||||||||
|
||||||||||||||||||||
|
||||||||||||||||||||
class EncryptedCacheProxy(object): | ||||||||||||||||||||
|
||||||||||||||||||||
def __init__(self, cache, registry, encrypter=None, decrypter=None): | ||||||||||||||||||||
|
@@ -437,11 +447,17 @@ def SETTINGS_MODULE(self): | |||||||||||||||||||
return self._get_default('SETTINGS_MODULE') | ||||||||||||||||||||
|
||||||||||||||||||||
def __getattr__(self, name): | ||||||||||||||||||||
if name.startswith('LOG_AGGREGATOR_'): | ||||||||||||||||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. cc @AlanCoding I think this is going to help a lot with performance across the board when external logging is enabled There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
It will help when external logging is not enabled. When we replaced service restarts with more frequent hits to memcache, this included tests for enablement. I'm wondering if there is anything we need to document this. And I think the answer is yes, but not much. Lines 701 to 709 in c33d2a1
Within this setting help text, I would suggest
I think that this per-process TTL could be rolled out as a parameter to settings definitions generally. In most cases, it probably still makes sense to not cache it locally like this, but there are still many cases where we check a value multiple times within the same request / operation, which is never a thing we should want to do. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That's true, but it yields even more of a boost when logging is enabled. I've set it to 5 seconds, so I question whether we need to do much to actually tell people about this, especially since the old behavior in prior releases was that we restarted actual processes. I think it's reasonable that it takes a few seconds for logs to show up. I expect it takes most mortals at least this long to switch the context of browser tabs and log in to/pull up logstash/Splunk, especially if you consider this enablement is probably something you ideally set up and get working once. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. cc @gamuniz |
||||||||||||||||||||
cached = LOGGING_SETTINGS_CACHE.get(name) | ||||||||||||||||||||
if cached: | ||||||||||||||||||||
return cached | ||||||||||||||||||||
value = empty | ||||||||||||||||||||
if name in self.all_supported_settings: | ||||||||||||||||||||
with _ctit_db_wrapper(trans_safe=True): | ||||||||||||||||||||
value = self._get_local(name) | ||||||||||||||||||||
if value is not empty: | ||||||||||||||||||||
if name.startswith('LOG_AGGREGATOR_'): | ||||||||||||||||||||
LOGGING_SETTINGS_CACHE[name] = value | ||||||||||||||||||||
return value | ||||||||||||||||||||
value = self._get_default(name) | ||||||||||||||||||||
# sometimes users specify RabbitMQ passwords that contain | ||||||||||||||||||||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -119,6 +119,9 @@ def stop(self, signum, frame): | |
|
||
class BaseWorker(object): | ||
|
||
def read(self, queue): | ||
return queue.get(block=True, timeout=1) | ||
|
||
def work_loop(self, queue, finished, idx, *args): | ||
ppid = os.getppid() | ||
signal_handler = WorkerSignalHandler() | ||
|
@@ -128,7 +131,7 @@ def work_loop(self, queue, finished, idx, *args): | |
if os.getppid() != ppid: | ||
break | ||
try: | ||
body = queue.get(block=True, timeout=1) | ||
body = self.read(queue) | ||
This comment was marked as resolved.
Sorry, something went wrong. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. no, looks like this change is just to accommodate the pattern in the callback-specific worker code There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right, this is just to persist the behavior for the base case (the dispatcher). |
||
if body == 'QUIT': | ||
break | ||
except QueueEmpty: | ||
|
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.
@AlanCoding I decided to change this back to 1 second, because I'm still seeing drastic speed improvements with 1 second, and it's likely to much less noticeable for users.
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.
well, no need to document that