-
Notifications
You must be signed in to change notification settings - Fork 21.6k
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
Refactor middleware stack to track delete middlewares #27936
Conversation
This way we only have one conditional.
middleware if it was deleted
The MiddlewareStack nows know how to handle already deleted middlewares.
Add test case for rails#26303
@rafaelfranca thank you for working on this. I appreciate the time you've put into it. Overall, it seems this approach will work; however, I do have a couple of concerns: First, suppose you have the following middleware stack: Alpha
Bravo Now suppose I delete Alpha
Delta Finally, if I add Alpha
Echo
Delta However, I would have expected One way to solve this is as follows: Rather than storing a |
My second concern is that if you delete a middleware and add it back into the stack in a different location, and then later you reference that middleware class when adding some other middleware, it's not obvious whether you intend to add relative to the deleted location or relative to the new location. I can see valid use cases for both. I think using the new location is slightly more intuitive, but either way seems that it would surprise one group of people or another. Edit To clarify, current Rails behavior uses whichever location is first in the stack (either the old deleted location, or the new location). This PR changes that behavior to always use the old deleted location. I understand you want a way to address #16433, but overall, I think the idea of handling middleware deletes as a special case leads to unintended surprises. Conceptually, the whole idea of adding middleware relative to other middleware (which may or may not be present in the stack) is intrinsically fragile, especially when 3rd parties are involved. Rather than Rails trying to "guess" what the user is trying to do (i.e. by handling deletes as a special case), perhaps it would be better to enhance the middleware API to allow 3rd parties to handle the fragility themselves. For example, If |
end | ||
|
||
def track_deleted_middleware_at(index) | ||
previous_middleware = middlewares[index - 1].klass |
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 doesn't work well if you delete the very first middleware. In such a case, the previous
pointer will point to the last middleware in the stack, so subsequent calls to insert relative to that pointer will put things near the end rather than near the beginning, for example.
Thank you for the feedback. You concerns are all valid. I'm not sure there is a way to fix both issues. Any middleware is optional so we need to have a way to handle changing the stack relative to other middleware. But at same time, changing the stack relative to other middleware is not intuitive as you pointed in both examples. I believe my solution is closer to the behavior we have since Rails 3.0 so even that is not intuitive to some people, it is already being here for more than 5 years and people is already familiar with it. |
@rafaelfranca thank you for your response. For my second example, I agree there really isn't a way to fix it, and there isn't a clear "best" way to pick which position to use. However, for my first example, I'm not sure I understand why you prefer the behavior in this PR over the existing behavior. In other words, why do you prefer Alpha
Echo
Delta instead of Alpha
Delta
Echo The latter matches the current Rails behavior (as well as intuition), but this PR changes it. Perhaps I misunderstood your reasoning as it applies to my first example. Thanks! |
assert_equal FooMiddleware, @stack.first.klass | ||
assert_equal BarMiddleware, @stack[1].klass | ||
assert_equal HiyaMiddleware, @stack[2].klass | ||
assert_equal false, @stack.include?(BazMiddleware) |
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.
assert_not_includes
?
Yeah, I was only talking about the second problem. The first one I need to fix. |
I would be happy to work on a fix for the the first one, if you would like. |
Sure. Feel free to open a pr against this branch
…On Wed, Feb 15, 2017 at 9:31 PM Nathan ***@***.***> wrote:
I would be happy to work on a fix for the the first one, if you would like.
—
You are receiving this because you were mentioned.
Reply to this email directly, view it on GitHub
<#27936 (comment)>, or mute
the thread
<https://github.com/notifications/unsubscribe-auth/AAC66GBiqaMO__TRhB_Va0Y3v-EDadP9ks5rc4rBgaJpZM4L54W6>
.
|
👍🏻 I like this because it retains the current simple, intuitive-most-of-the-time API. We could replace the middleware management API entirely, and switch to full explicit dependencies -- essentially promoting 6b126ff to runtime. But I think I still prefer the explicitness of a static list. |
FYI: I wrote code for this a few months ago in a PR into this branch here: rafaelfranca#2 Please let me know if there is anything else I can do to move this forward. The basic approach of my PR is this: Deleting a middleware doesn't actually remove the middleware; instead, it replaces it with an instance of a wrapper class that knows about the original. When enumerating over the middleware list, these wrappers are ignored (effectively treating them as if they aren't there), but they maintain the place of the deleted middleware so that future inserts can reference the deleted middleware and be placed in exactly the right place relative to where the deleted middleware would have been if it hadn't been deleted. |
@rafaelfranca Is this likely to be included in the next release? Currently the published work-arounds do not work and there is effectively no way to move an entry in the set. |
It may not cover all use cases, but I recently released a gem called rails-middleware-extensions that could help with this issue. Specifically it adds |
This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. |
@rafaelfranca Did this get blocked on something? |
This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. |
Still lgtm. Worth reviving @rafaelfranca? |
This pull request has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. |
Right now it is hard to re-insert delete middleware in the stack. The reason is that we only apply the delete operations after the insert operations and this will remove the middleware in the end.
To fix this instead of recording the delete operations separately in the MiddlewareStackProxy we keep track of deleted middleware so it is possible to add after and before them.
Fixes #26303 without reverting #16433.
cc @naw @sirupsen @tgxworld.