[Catalyst] Chained and exceptions
I have a feeling I asked this before, but cannot find the post. [info] Exception powered by Catalyst 5.90030 What's the reasoning that chained actions continue to run after an earlier exception? sub start : Chained( '/' ) : CaptureArgs(0) { warn in start\n; } sub middle : Chained( 'start' ) : CaptureArgs(0) { warn in middle\n; die died in middle\n; # or e.g. throw access violation } sub lastpart : Chained( 'middle' ) : Args(0) { my ( $self, $c ) = @_; $c-res-body( finished\n ); warn in lastpart\n; } $ script/exception_test.pl /start/middle/lastpart in start in middle *in lastpart* [error] Caught exception in Exception::Controller::Root-middle died in middle -- Bill Moseley mose...@hank.org ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Chained and exceptions
On 05/09/2013 03:25 PM, Bill Moseley wrote: I have a feeling I asked this before, but cannot find the post. [info] Exception powered by Catalyst 5.90030 What's the reasoning that chained actions continue to run after an earlier exception? sub start : Chained( '/' ) : CaptureArgs(0) { warn in start\n; } sub middle : Chained( 'start' ) : CaptureArgs(0) { warn in middle\n; die died in middle\n; # or e.g. throw access violation } sub lastpart : Chained( 'middle' ) : Args(0) { my ( $self, $c ) = @_; $c-res-body( finished\n ); warn in lastpart\n; } $ script/exception_test.pl http://exception_test.pl /start/middle/lastpart in start in middle *in lastpart* [error] Caught exception in Exception::Controller::Root-middle died in middle Hi Bill, This is because you don't want Catalyst to die. Imagine you are running a fastcgi server and you accidentally created an action which dies on certain user input. If Catalyst would die, the fastcgi server would die and your whole application would not be available anymore. Instead, you want to report the incident and keep the fastcgi server (Catalyst) running. Because of this, every action is wrapped in an eval{...}. Potential errors are logged, but the server keeps running. See execute in Catalyst.pm for implementation details. To solve your problem, you can wrap your unsafe code in an eval or use Try::Tiny (or whatever you prefer) and detach if the unsafe code dies. Your Example would look like this: use Try::Tiny; sub start : Chained( '/' ) : CaptureArgs(0) { warn in start\n; } sub middle : Chained( 'start' ) : CaptureArgs(0) { my ($self, $c) = @_; warn in middle\n; try{ die died in middle\n; # or e.g. throw access violation } catch{ $c-detach }; } sub lastpart : Chained( 'middle' ) : Args(0) { my ( $self, $c ) = @_; $c-res-body( finished\n ); warn in lastpart\n; } If you do it like this, actions chained to the unsafe action will not get executed if the unsafe action dies. In your case, lastpart will never be executed, because middle always dies. Lukas ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Chained and exceptions
On Thu, May 9, 2013 at 7:25 AM, Lukas Thiemeier spamcatc...@thiemeier.netwrote: On 05/09/2013 03:25 PM, Bill Moseley wrote: I have a feeling I asked this before, but cannot find the post. [info] Exception powered by Catalyst 5.90030 What's the reasoning that chained actions continue to run after an earlier exception? sub start : Chained( '/' ) : CaptureArgs(0) { warn in start\n; } sub middle : Chained( 'start' ) : CaptureArgs(0) { warn in middle\n; die died in middle\n; # or e.g. throw access violation } sub lastpart : Chained( 'middle' ) : Args(0) { my ( $self, $c ) = @_; $c-res-body( finished\n ); warn in lastpart\n; } $ script/exception_test.pl http://exception_test.pl /start/middle/lastpart in start in middle *in lastpart* [error] Caught exception in Exception::Controller::Root-middle died in middle Hi Bill, This is because you don't want Catalyst to die. Imagine you are running a fastcgi server and you accidentally created an action which dies on certain user input. Hi Lukas, Sorry, you missed the point. Yes, Catalyst traps exceptions. That is expected and is done in handle_request when calling $c-dispatch. I'm talking about breaking a chain of actions. Why would a later part of the chain run if an earlier part threw an exception. For example, what if an earlier part of a chain threw a access violation. In that case you would not want the later chain to run. If Catalyst would die, the fastcgi server would die and your whole application would not be available anymore. Instead, you want to report the incident and keep the fastcgi server (Catalyst) running. Because of this, every action is wrapped in an eval{...}. Potential errors are logged, but the server keeps running. See execute in Catalyst.pm for implementation details. To solve your problem, you can wrap your unsafe code in an eval or use Try::Tiny (or whatever you prefer) and detach if the unsafe code dies. Your Example would look like this: use Try::Tiny; sub start : Chained( '/' ) : CaptureArgs(0) { warn in start\n; } sub middle : Chained( 'start' ) : CaptureArgs(0) { my ($self, $c) = @_; warn in middle\n; try{ die died in middle\n; # or e.g. throw access violation } catch{ $c-detach }; } Don't forget your semicolon. :) sub lastpart : Chained( 'middle' ) : Args(0) { my ( $self, $c ) = @_; $c-res-body( finished\n ); warn in lastpart\n; } If you do it like this, actions chained to the unsafe action will not get executed if the unsafe action dies. In your case, lastpart will never be executed, because middle always dies. Lukas ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/ -- Bill Moseley mose...@hank.org ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Chained and exceptions
On Thu, May 9, 2013 at 8:31 AM, Bill Moseley mose...@hank.org wrote: Hi Bill, This is because you don't want Catalyst to die. Imagine you are running a fastcgi server and you accidentally created an action which dies on certain user input. Hi Lukas, Sorry, you missed the point. Yes, Catalyst traps exceptions. That is expected and is done in handle_request when calling $c-dispatch. No, sorry, I responded too quickly. I'm not talking about the entire have exiting, of course. I'm just not sure it makes sense to not check $c-errors after calling each action in a chain. What's the use case for that? -- Bill Moseley mose...@hank.org ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Re: Chained and exceptions
On Thu, May 9, 2013 at 9:34 AM, Aristotle Pagaltzis pagalt...@gmx.dewrote: * Bill Moseley mose...@hank.org [2013-05-09 15:30]: What's the reasoning that chained actions continue to run after an earlier exception? Seems like an accident of the design to me, borderline bug. Agreed. Seems like something that could be easily overlooked. If like me you don’t like it, Catalyst::ActionRole::DetachOnDie Oh, that's nice. Tricks for applying it globally? I went the monkey patch route. Shield your eyes: use Catalyst::ActionChain; sub Catalyst::ActionChain::dispatch { my ( $self, $c ) = @_; my @captures = @{$c-req-captures||[]}; my @chain = @{ $self-chain }; my $last = pop(@chain); foreach my $action ( @chain ) { my @args; if (my $cap = $action-number_of_captures) { @args = splice(@captures, 0, $cap); } local $c-request-{arguments} = \@args; $action-dispatch( $c ); * return if @{ $c-error }; # Patch* } $last-dispatch( $c ); } -- Bill Moseley mose...@hank.org ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/
Re: [Catalyst] Re: Chained and exceptions
Blast from the past: http://grokbase.com/t/sc/catalyst/077e7jhw9g/rfc-catalyst-plugin-errorout On Thu, May 9, 2013 at 1:42 PM, Bill Moseley mose...@hank.org wrote: On Thu, May 9, 2013 at 9:34 AM, Aristotle Pagaltzis pagalt...@gmx.dewrote: * Bill Moseley mose...@hank.org [2013-05-09 15:30]: What's the reasoning that chained actions continue to run after an earlier exception? Seems like an accident of the design to me, borderline bug. Agreed. Seems like something that could be easily overlooked. If like me you don’t like it, Catalyst::ActionRole::DetachOnDie Oh, that's nice. Tricks for applying it globally? I went the monkey patch route. Shield your eyes: use Catalyst::ActionChain; sub Catalyst::ActionChain::dispatch { my ( $self, $c ) = @_; my @captures = @{$c-req-captures||[]}; my @chain = @{ $self-chain }; my $last = pop(@chain); foreach my $action ( @chain ) { my @args; if (my $cap = $action-number_of_captures) { @args = splice(@captures, 0, $cap); } local $c-request-{arguments} = \@args; $action-dispatch( $c ); * return if @{ $c-error }; # Patch* } $last-dispatch( $c ); } -- Bill Moseley mose...@hank.org ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/ ___ List: Catalyst@lists.scsys.co.uk Listinfo: http://lists.scsys.co.uk/cgi-bin/mailman/listinfo/catalyst Searchable archive: http://www.mail-archive.com/catalyst@lists.scsys.co.uk/ Dev site: http://dev.catalyst.perl.org/