-
-
Notifications
You must be signed in to change notification settings - Fork 2.3k
Add concurrency safe context option. #1158
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
Add concurrency safe context option. #1158
Conversation
Codecov Report
@@ Coverage Diff @@
## master #1158 +/- ##
==========================================
+ Coverage 81.78% 81.82% +0.03%
==========================================
Files 26 26
Lines 1933 1937 +4
==========================================
+ Hits 1581 1585 +4
Misses 243 243
Partials 109 109
Continue to review full report at Codecov.
|
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
Is this explicitly not desired or has it been missed? I can close it with no problem if it's not in the Echo vision. |
Most likely missed @andreiavrammsd Thank you for the PR. Looks like a good idea to me. In fact I don't see why anyone would prefer the unsafe version. Thoughts @vishr @im-kulikov ? In fact, I would propose an "opposite" PR: change Echo so that safe is the default option and add an |
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. It's interesting, but I'm leaning towards @alexaandru. This way, we won't break backward compatibility and give additional features to those who really need it.
@im-kulikov, wouldn't it break compatibility if |
hmmm.. make sense... |
I think there's been a misunderstanding. It will be more predictable if the context is to be thread safe out of the box. |
If anyone depends on their application crashing, then there's a very easy fix for that: just use Now joking aside, I don't see how anyone could raise the "backward compatibility" card, when all we're doing is touching the internals and eliminate a possible crash condition. No signature changes, we don't remove anything from the public interface, we simply ensure that under certain conditions, the app will not crash. Now OTOH, not sure that having all requests both write and read from context is by itself a good pattern. If you need all your requests to do that concurrently, probably you're missing a datastore of some sort (could be in memory, Redis, BoltDB, whatever). I mean locks only ensure it is safe to do so, but it doesn't make it right :-) Which is probably one of the reasons why no one complained about it so far... I still think we should fix it, I just think we should not encourage using context like it's some sort of database. |
One could argue that locking is degrading performance, but if you get to this situation, you'll be able to use the I'll update the PR with the opposite implementation by adding the |
Yeah one could try to argue that, but it would be a weak argument. There's no framework that I know of that has the speed as part of their public interface. Nowhere in the README (or any other docs) does Echo say "a request should complete within X ms". I think we're safe :-) Thank you for updating the PR! |
cb0d7de
to
8c4fa85
Compare
@alexaandru, @im-kulikov, please take a look. |
@andreiavrammsd could you please squash the branch? Makes it easier to review/comment on it. Thanks! |
8c4fa85
to
e70766a
Compare
Sure, it's done. |
Thank you @andreiavrammsd :) Looks good to me! @im-kulikov @vishr ? |
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.
🎉 Great job! Thanks. SGTM
LGTM, ok to merge. I updated this issue labstack/echox#37. We need to find time to update the docs. |
@alexaandru |
Also, benchmarks using a regular map indicate zero allocations, while a Mutex: Both executed with: I believe a simple map is safer for any use case a user may have. The code with
And if you still want to offer the Benchmarks environment:
|
Got it, I am a little reluctant to introduce a new option and would favor it as default. Can you run a benchmark test (already in the repo) to see if there is any different with/without lock or is it even in the path? |
Yup, the docs need some love :-) I'll be happy to take a stab at that, but only a little later this month. First, I want to help close as many tickets and PRs as possible, after that I'll focus on the docs. |
@vishr He did provide the benchmarks in the initial post: 545 ns/op with locks vs 408 ns/op without. So let's see, what options we have:
As I already said, I believe the case of heavy read/write from/to context would be rather the exception than the norm. The context is not a database... :-) The option no. 3 starts to sound appealing to me... :-) |
I saw those and we should be ok with that difference. However, I was referring to routing benchmarks https://github.com/labstack/echo/blob/master/router_test.go#L935, if these are not affected - we should be good. |
Why would the router be affected? I don't see how the lock is attained in the router. Am I missing something? Anyway, I ran the router benchmarks twice for each branch:
Indeed, if "it doesn't feel right" it can be a good idea to leave everything as it is, like @alexaandru said, and just clearly state the situation in the docs and give the custom context solution (it's actually what I did on the project where I met the issue). |
Just wanted to double check it's been long time ;). I would propose to make |
@vishr that's exactly how the PR works right now (Get/Set protected by a lock, by default). Only if end users opt in to avoid locking, they can do so. Are you OK with keeping the new option If we keep it, there's a couple suggestions I have: 1) let's make it clear that it is solely for backward compatibility purposes and we do not recommend it (including in the commit message but also in the docs) and 2) possibly mark it as obsolete and "to be removed in the next major version" ? I mean, we should just be safe by default... For the few cases where this will impact their performance, maybe it's worth the trouble of adding it, but long term I don't think we should keep it. Also, if you're suggesting to remove the unsafe option, I'm not opposed to that :-) |
I don't want to introduce another option in the code. The overhead of a lock is negligible - let's keep it by default. |
Works for me! :-) |
e70766a
to
a91ca8c
Compare
Please trigger the Travis build, it looks like it got stuck. |
thanks for your contribution 🎉 |
Thank you, too, for your time! |
Update: Safe context is used by default, with no option to disable it.
Update: Safe context is by default, with the option to use it unsafe.
If SafeContext option set to true on an Echo server instance, contexts will be concurrency safe.
I met the #273 issue while running GraphQL with concurrent resolvers, and I think it would be nice to offer the option of concurrency safe contexts.
Usage
Benchmarks