I experienced some trouble using resignalling. I have a method
jsonRequestBodyWith: aClass ^ [ COJsonParser parse: self requestContext request bodyDecoded for: aClass new ] on: Error do: [:error| error resignalAs: (COContentError new messageText: 'cannot parse content')] If an error occurs the VM blocks the request and goes on 100% CPU usage. Is resignalling problematic from within a on:do: block? Rewritting the method to jsonRequestBodyWith: aClass | object errorOccurred | errorOccurred := false. object := [ COJsonParser parse: self requestContext request bodyDecoded for: aClass new ] on: Error do: [:error| errorOccurred := true ]. errorOccurred ifTrue: [ (COContentError new messageText: 'cannot parse content') signal ]. ^ object works as expected. Any thoughts? thanks, Norbert |
Norbert,
We think that the behavior you are seeing is correct (according to ANSI) .... IIRC, there is a bug exception handling related to this that exists in Pharo and GemStone 2.x (recall the continuation trouble that was reported by the VW folks?)... According to ANSI when resignalling: "The active exception action is aborted and the exception environment and the evaluation context are restored to the same states that were in effect when the receiver was originally signaled. Restoring the evaluation context may result in the execution of #ensure: or #ifCurtailed: termination blocks. After the restoration, signal the replacementException and execute the exception action as determined by the restored exception environment. This message causes the replacementException to be treated as if it had been originally signaled instead of the receiver." The implication is that the resignalAs: inside the handler block SHOULD be caught by the ERROR handler (giving you an infinite loop) ... so the alternatives are to resignalAs: an something other than Error or to SIGNAL the new error (not resignal) from the handler block. You should use resignalAs: if you expect a handler for COContentError to exist between the original signal site and the current site .... BTW, thanks for the report though, because it's not always obvious what's expected behavior and what's not:) Dale ----- Original Message ----- | From: "Norbert Hartl" <[hidden email]> | To: "GemStone Seaside beta discussion" <[hidden email]> | Sent: Friday, February 8, 2013 3:41:37 AM | Subject: [GS/SS Beta] resignalling of an error | | I experienced some trouble using resignalling. I have a method | | jsonRequestBodyWith: aClass | ^ [ COJsonParser parse: self requestContext request bodyDecoded for: | aClass new ] | on: Error | do: [:error| | error resignalAs: (COContentError new messageText: 'cannot parse | content')] | | If an error occurs the VM blocks the request and goes on 100% CPU | usage. Is resignalling problematic from within a on:do: block? | Rewritting the method to | | jsonRequestBodyWith: aClass | | object errorOccurred | | errorOccurred := false. | object := [ COJsonParser parse: self requestContext request | bodyDecoded for: aClass new ] | on: Error | do: [:error| errorOccurred := true ]. | errorOccurred ifTrue: [ | (COContentError new messageText: 'cannot parse content') signal ]. | ^ object | | works as expected. | | Any thoughts? | | thanks, | | Norbert |
Dale,
thank you very much. I didn't get the important part. But your explanation made it very clear. Comments inline! Am 09.02.2013 um 01:51 schrieb Dale Henrichs <[hidden email]>: > Norbert, > > We think that the behavior you are seeing is correct (according to ANSI) .... IIRC, there is a bug exception handling related to this that exists in Pharo and GemStone 2.x (recall the continuation trouble that was reported by the VW folks?)... According to ANSI when resignalling: > > "The active exception action is aborted and the exception environment and the evaluation context > are restored to the same states that were in effect when the receiver was originally signaled. > Restoring the evaluation context may result in the execution of #ensure: or #ifCurtailed: > termination blocks. > > After the restoration, signal the replacementException and execute the exception action as > determined by the restored exception environment. > > This message causes the replacementException to be treated as if it had been originally > signaled instead of the receiver." > > The implication is that the resignalAs: inside the handler block SHOULD be caught by the ERROR handler (giving you an infinite loop) ... so the alternatives are to resignalAs: an something other than Error or to SIGNAL the new error (not resignal) from the handler block. > > You should use resignalAs: if you expect a handler for COContentError to exist between the original signal site and the current site …. > I just need to take another approach. While translating one exception to another I'm just not allowed to catch for any common root of both exceptions. I cannot test it right now. But I think using … on: WAError do: [:error| error resignalAs: (COContentError new messageText: 'cannot parse content')] will do the trick because COContentError will miss this exception handler block. Now I'm just not sure if it is good or harmful to have ensure:/ifCurtailed: called before my exception is taking off. At least now that I know I have the choice. Thank you! Norbert > BTW, thanks for the report though, because it's not always obvious what's expected behavior and what's not:) > > Dale > > ----- Original Message ----- > | From: "Norbert Hartl" <[hidden email]> > | To: "GemStone Seaside beta discussion" <[hidden email]> > | Sent: Friday, February 8, 2013 3:41:37 AM > | Subject: [GS/SS Beta] resignalling of an error > | > | I experienced some trouble using resignalling. I have a method > | > | jsonRequestBodyWith: aClass > | ^ [ COJsonParser parse: self requestContext request bodyDecoded for: > | aClass new ] > | on: Error > | do: [:error| > | error resignalAs: (COContentError new messageText: 'cannot parse > | content')] > | > | If an error occurs the VM blocks the request and goes on 100% CPU > | usage. Is resignalling problematic from within a on:do: block? > | Rewritting the method to > | > | jsonRequestBodyWith: aClass > | | object errorOccurred | > | errorOccurred := false. > | object := [ COJsonParser parse: self requestContext request > | bodyDecoded for: aClass new ] > | on: Error > | do: [:error| errorOccurred := true ]. > | errorOccurred ifTrue: [ > | (COContentError new messageText: 'cannot parse content') signal ]. > | ^ object > | > | works as expected. > | > | Any thoughts? > | > | thanks, > | > | Norbert |
In reply to this post by NorbertHartl
> Date: Sat, 9 Feb 2013 14:41:27 +0100
> From: Norbert Hartl <[hidden email]> > > Dale, > > thank you very much. I didn't get the important part. But your explanation made it very clear. > Comments inline! > ... > > What I'm doing here is translating a seaside exception to an exception of my own business model. > And this exception will be mapped to the corresponding HTTP status returned. This way it is not > easy to have my own exception handler between the original and the current site. > I just need to take another approach. While translating one exception to another I'm just not > allowed to catch for any common root of both exceptions. I cannot test it right now. But I think using > > ? > on: WAError > do: [:error| > error resignalAs: (COContentError new messageText: 'cannot parse content')] > > will do the trick because COContentError will miss this exception handler block. Now I'm just not > sure if it is good or harmful to have ensure:/ifCurtailed: called before my exception is taking off. > At least now that I know I have the choice. Thank you! Norbert, I generally would recommend against resignalling a *different* error. If you *wrap* the original error in your new COContentError exception, you then retain a record of *why* it failed, rather than just the fact that it did fail. The usual practice is create and throw a new exception from the handler. There are times when resignalling a different exception is a good idea, but at first glance, this does not seem like the place to do it. Good luck, Richard Sargent |
Free forum by Nabble | Edit this page |