This repository has been archived by the owner on Apr 26, 2024. It is now read-only.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Fix incorrect juggling of logging contexts in
_PerHostRatelimiter
#13554Fix incorrect juggling of logging contexts in
_PerHostRatelimiter
#13554Changes from all commits
a30c01b
b0e018c
00d0644
9245646
b999888
b7b50a7
0bdce68
dccbb75
4a398f9
File filter
Filter by extension
Conversations
Jump to
There are no files selected for viewing
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.
Is there discussion somewhere about how this fixes the log context? Trying to learn and understand.
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.
@MadLittleMods there was some discussion in Backend Internal (https://matrix.to/#/!SGNQGPGUwtcPBUotTL:matrix.org/$xqpsbzDjJpmqAt9xTBtpS6qAAWXrBv3N_HkjwwK2QoM?via=jki.re&via=matrix.org&via=element.io), but I don't think there's much detailed discussion.
As @squahtx said:
In other words:
make_deferred_yieldable
adds a callback to the deferred, and that callback would restore the logcontext created bystart_active_span
once the ratelimit wait completed.It might also be instructive to look at @squahtx's initial fix for this, which effectively just moved the call to
make_deferred_yieldable
to before the call tostart_active_span
. That was an entirely valid fix, we just decided that doing it this way felt more natural and more obviously correct.The lesson I take here (other than that logcontexts are confusing, which we knew) is that
__enter__
and__exit__
are hazardous materials and it's best to avoid messing with them directly where possible.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.
It's a subtlety in the way spans, logging contexts and make_deferred_yieldable work.
Spans are implemented on top of logging contexts. That is, every span creates its own nested logging context (minus an optimization).
Just before
make_deferred_yieldable
is called, the active logging context is the one associated withspan
.make_deferred_yieldable
is a little big magical. It clears the active logging context and attaches a callback toret_defer
to restore the logging context after the deferred has resolved. With the previous code, the order of callbacks on ret_defer was:(on_start, on_err)
on_both
, callingspan.__exit__
and restoring the parent span's logging context.make_deferred_yieldable
's callback to restore the childspan
's logging context.But we need 2 and 3 to be the other way around. The child logging context needs to be restored, then
__exit__
ed, which makes it restore the parent logging context.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.
Wow, this is subtle!
@squahtx's initial fix is useful to look at 👍 But I think the initial fix does something a little different than this description. It moves the
span.__exit__()
after themake_deferred_yieldable
so thatmake_deferred_yieldable
's callback restores span's logging context. And thenspan.__exit__()
restores the parent context. From my understanding, this also aligns with what @squahtx mentions is the subtlety.But moving the call to
make_deferred_yieldable
to before the call tostart_active_span
sounds like it would work as well. That way thespan.__exit__()
would restore the nested context and thenmake_deferred_yieldable
's callback would restore the parent logging context.In any case, we want the parent logging context restored when we get out of everything (fold and unfold in the correct order).
Now in the final form of the fix, the
span
is entered via thewith
context manager so it has the outermost parent context, thenmake_deferred_yieldable
is called which is in thespan
context. And because we are using the properwith
nesting context manager stuff it also properly unfolds in the correct order:make_deferred_yieldable
's callback restores thespan
context, and thespan
context manager exit restores the parent context.🎉
Thanks for explaining @richvdh and @squahtx ❤️
The key pitfall in my change is not knowing the magic in
make_deferred_yieldable
: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.
You're right, sorry, my description of @squahtx's fix was incorrect.
Actually it seems it wouldn't. We tried something equivalent in this thread and as @squahtx points out there are other problems.