resignalling of an error

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
4 messages Options
Reply | Threaded
Open this post in threaded view
|

resignalling of an error

NorbertHartl
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
Reply | Threaded
Open this post in threaded view
|

Re: resignalling of an error

Dale Henrichs
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
Reply | Threaded
Open this post in threaded view
|

Re: resignalling of an error

NorbertHartl
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 ….
>
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

> 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

Reply | Threaded
Open this post in threaded view
|

Re: resignalling of an error

Richard Sargent (again)
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