-
Notifications
You must be signed in to change notification settings - Fork 274
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
Current use of Return::MultiLevel silently and unexpectedly breaks program flow #1125
Comments
Also highlighting @melo (who had the safer more conservative idea back then #432 (comment)) and @mauke (in case he has any thoughts on how |
@ribasushi You missed a later comment. |
@xsawyerx Indeed I have. Thoughts on the rest of the ticket? |
Honestly, I don't think I understand it. I'm not that fast on my feet today. :/ |
"Flow control based on recoverable errors" is a thing we all use a lot. Let's take an example from Dancer2 itself. Now imagine that someone happened to do:
Now your soft-failure handler will never be reached, because we just sent the user to the homepage. You (correctly I must add) did not expect that the eval{} could never return. Dancer2 broke this implicit contract by using R::ML. One might argue that the user hooking Does this explanation help? |
I agree that $SIG{DIE} is very dangerous, as all side effects are. It is not needed for D2::P::LR when used with Log::Report::try() because that will decide (accidental) dies into exception objects. You should never need the given example. For me, the hardest thing in programming is the program flow for handling/recovering error conditions. How can you implement that correctly when the program itself can escape from logic via Return::MultiLevel? I do not known much about Dancer2 internals. Isn't it possible to let 'forward' come back to the place where it is called? |
In terms of the plugin, I will look and see if we can change its behaviour to return a rendered error page instead of executing a redirect. Nonetheless, the problems highlighted by this issue do seem rather undesirable. We are effectively inserting goto statements into people's code, without them realising it. To give another (probably related) example, the forking code at the following link is sometimes leaving unreaped zombies. It is so intermittent that I haven't been able to find the cause, but |
@markov2 What |
IME, there are just some problems where coding around the users lack of understanding is not the right choice. You're constrained by the design of the language and the mechanics of that language, if the user doesn't understand why their programming language doesn't do what they expect it to do, they should change their expectations. Radically changing the language ( and breaking the assumptions made by all code written in that language ) to cater to bad expectations seems like a bad trade-off. |
On Thu, 4 Feb 2016, Sawyer X wrote:
[FWIW] return redirect '/foo/bar' if some_condition; |
Separation of concerns is also just as important (IME). Logging your apps' (model) interactions should be independent of any HTTP request. It looks like D2:P:LR tangles up these concerns, doing a HTTP redirect inside a logging handler. The use of Return::MultiLevel implicitly adds to that spaghetti. I haven't had a chance to verify if the existing |
Other than the fact that Dancer2's DSL is DSL (and is supposed to be more than just syntax, but a mini language onto its own), and ignoring the fact that Dancer2 actually uses its shiny (for different values of "shiny", I suppose) syntax to attract non-Perl developers (relatively successfully, IMHO), removing We cannot just break a substantial amount of applications. |
Here's some random thoughts of mine: I'm not familiar with Dancer2 or DBIx::Class. I've read bits of this discussion and some of the documentation. DBIC's Here are some other things that the
None of these are "radically changing the language"; they're just what the mechanics of Perl allow. That said, I don't understand what the purpose of What's the point of using (It's probably not that easy. Feel free to tell me exactly why that won't work. :-) I haven't actually looked at any code.) |
This is a valid expectation and will be the case as of the next major release.
The point of this ticket is that there are many many more ways for unexpected behavior to creep in, just as demonstrated here. |
D2::P::LR is throwing an exception. One of the several things that are done when that exception is "actioned" (including logging to syslog etc) is to redirect the user to a "safe" page. The problem is that the redirect is then effectively goto-ing out of that exception block, so it never gets caught by DBIC. I'm not saying that the plugin's behaviour is correct, nor that it can't be fixed. I'm sure it can, and I'll be looking at solutions to that. The point of this issue is that it has happened, it has caused some rather strange bugs, and has required a lot of debugging. |
Indeed, the decision was made a couple of years ago. Whether it is a good idea or not is now largely academic. Nonetheless, I do think some sort of warning system is needed to catch this happening again, as it surely will. Some sort of guard that will carp when it detects the situation. I would offer to write such a patch, but I do not currently have the required knowledge, but I think the issue should remain open until someone is able to. Any other similar situations should also be caught and warned about, as it does worry me that I or others may have made similar assumptions elsewhere. |
This custom flow control system, "Special DSL for Dancer" or not, in practice means that Dancer cannot be expected to safely mix-and-match with arbitrary CPAN Libraries without first having to independently vet them for this specific issue first. Given Dancer has a stated goal of bringing people to Perl, I see a significant conflict of interest by having a design that prevents non-Perl developers from using CPAN and Dancer together with expectations of safety. I can appreciate the feature as-is being removed will cause headaches, but I'd rather we discouraged what is effectively a "goto $label hidden in a pretty API" from being further proliferated. |
Considering changing this behavior will break user applications in very subtle and horrible ways, it is clear that it cannot simply be changed and possibly cannot be changed at all. This means that this is not the forum to discuss whether this is effective outreach or whether we should generally discourage this practice. That does not change anything at hand and I don't want this ticket to become a place to debate this behavior, only how to solve the problem we have at hand. I think @mauke gives interesting ideas that we should reflect on, understand, and possibly apply. That's what I would like to focus on. |
Incidentally, "goto $label hidden in a pretty API" is exactly what I think exceptions are. |
@mauke right, and Dancer 1 used exceptions for this rather than RML, and that was just a different sort of footgun. The trick will be finding a way to warn the user where they're pointing it. I'll have a think about it. |
(in 20/20 hindsight I think we should've called the immediate one redirect_immediate or redirect_now, but it totally didn't occur to me at the time so shrug) |
There is no reason we can't reverse @shadowcat-mst's suggestion and add a |
@abeverley is there a public source repository for D2::P::LR ? |
There are public sources, why would you like to have a public repository?greetz, drs Mark A.C.J. Overmeer MARKOV Solutions |
@markov2 history. You can read a changelog and you can download several versions and diff them; but its 'metadata' like commit messages and references to issues (that are otherwise not in comments) that help to understand why somethings were done the way they were. I don't have any specific examples for Log::Report, but I do find |
There's not I'm afraid Rusty. Do you have any specific questions I can help with? |
Why not, @abeverley ? It makes a lot of sense for open source software. |
In this case, that's not a choice made by Andy, but by me: at the moment, There is a major misconception about Open Source in relation to GitHub. "GitHub" means that your development process is visible. When I develop, Release often with ChangeLog has proven to be a very good development model for me. Totally Open Source.Regards, drs Mark A.C.J. Overmeer MARKOV Solutions |
What "makes sense" for open source doesn't always fit what needs to be done in practice. Open Source can be developed openly or privately, and that's up to the person writing it or in charge of it. |
I use git(hub) for some projects, and do not use it for other projects. For complex libraries, I do not get any correct fix so why should I
For me, it is either git or backups to do my version control.Regards,
|
If anyone has an implementation which will work, or a way to implement the same thing, or a way to minimize the possible side-effects that caused this ticket to be raised, I would be more than happy. As it stands, just "remove this module" will not happen. I vote for closing this issue. |
Given my non-involvement in Dancer2 I do not have anything further to add besides the initial investigation/diagnosis/recommendation. I vote "whatever" ;) |
I would say that as a minimum, the documentation needs some warnings. Ideally, the code should also warn appropriately.
I think the issue should remain open until the above has happened. I am happy to draft appropriate documentation updates when I get a moment. |
Pointed out by Lukas Mai in the last (fifth) bullet point of PerlDancer/Dancer2#1125 (comment) In addition add extra testing making sure that we will not inadvertently silence $SIG{__DIE__} when the error is *not* transient Hopefully this is the last piece of the "clean transient exceptions" puzzle, it's already been way too much faffing: 7cb3585, ddcc02d and 5c33c8b :(
@abeverley and I sat to discuss this and decided that the plugin in question could use a different mechanism or document its current behavior. There were two options and both were considered "consistent" for different considerations. It is up to the author to decide which consistency is desired and to document it appropriately. One was that anything in the web environment redirects (which cannot be controlled), even from within another plugin, or that only the Dancer2 plugin redirects. Both of these options are possible for the author to choose. I don't agree that having a module return from an upper frame without you being able to trap it is necessarily incorrect[1], and that here there was, IMHO, a design decision on the plugin's side - to which a solution was found - I am closing this issue, to the content of both myself and the user (@abeverley). [1] Sorry. |
While on its surface #485 is a good idea, it comes with a huge footgun as can be seen here
The real-life implication of this is that anyone following the advice in Dancer2::Plugin::LogReport completely breaks their DBIC retry logic and possibly other parts of their model, as the internals are not prepared for longjmp's from the middle of its exception stacks.
While detecting the problem is relatively easy, protecting a large project from this is extremely involved (and expensive performance-wise).
I strongly recommend that the use of
Return::MultiLevel
is re-thought in light of this.Highlighting @markov2 and @abeverley in case they decide to change
D2::P::LR
ahead ofD2
itself.The text was updated successfully, but these errors were encountered: