One challenge I've noticed in several of my recent apps is dealing with
ensure: and critical: and friends in cases where Seaside's session error handler deals with an error. (BTW, this is conceptually different than the case where we want to avoid call: inside such blocks.) One has domain code called from a Seaside application and the domain code signals an otherwise unhandled exception. These can be deep in the domain model where one shouldn't be conscious of Seaside at all. Unfortunately the converse is true as well, there is no way for UI level code to know of a protected block deep in the model. What I'd like is a trick to write a Seaside exception handler that conceptually looks like: handleError: anError anError unwindTo: the place where the session installed an error handler. display a document I see an implementation of Exception>>unwindTo: but no senders or tests so I'm not sure it even works (or does what I think it does). Of course, in response to this, many Seasiders already use critical:ifError: inside their model code but this ruins debugging. The rough equivalent for ensure: is: BlockContext>>reallyEnsure: aBlock self on: Error do: [:ex | aBlock value. ex pass] I generally don't worry about non Error-type exceptions but these could be dealt with here as well. Of course you can't retry, return etc. on the notification once you've finalized your resources. Exceptions: with great power comes great responsibility ;-) reallyEnsure:, like critical:ifError:, makes debugging a challenge since whatever resources are being freed by aBlock are needed if we want to raise a debugger. In short the current behavior works great for debugging but in production leaves resources "unfinalized" whereas my solutions ruin debugging but make sure that finalization happens. Anyone found a better solution? David _______________________________________________ Seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
C. David Shaffer wrote:
> [snip] > > I see an implementation of Exception>>unwindTo: but no senders or > tests so I'm not sure it even works (or does what I think it does). > Oops, that should be ContextPart>>unwindTo: emphasizing even more that I have no idea what I'm talking about ;-) David _______________________________________________ Seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
In reply to this post by cdavidshaffer
In continuing the process of answering myself...
I tried: [ [1/0] ensure: [Transcript show: 'got it.'; cr]. Transcript show: 'should not get here.'; cr ] on: Error do: [:ex | |signalContext handlerContext| signalContext := ex instVarNamed: #signalContext. handlerContext := ex instVarNamed: #handlerContext. signalContext unwindTo: handlerContext. self halt] Seems to work as expected ('got it' shows up in transcript before one quits the debugger). So, I'm trying: ProductionErrorHandler>>handleError: ex |signalContext handlerContext| signalContext := ex instVarNamed: #signalContext. handlerContext := ex instVarNamed: #handlerContext. signalContext unwindTo: handlerContext. WACurrentSession value returnResponse: (WAResponse document: self document mimeType: 'text/html') for a bit to see how it goes. If it seems right I'll embed it in exception and avoid all the instVarNamed: stuff. This makes ensure: and critical: release their resources since there is no hope of re-entering their contexts. David _______________________________________________ Seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
Hi David,
I'm not sure I really understand your question. There is a place in the code for handling exceptions. If you make your own subclass of WASession then you can implement something like this: withErrorHandler: aBlock "override and extend the basic seaside exception handling" ^[[super withErrorHandler: [aBlock on: USMRSDBObjectRegister do: [:ex | self registerObject: ex object. ex resume]]] on: USMRSDBProxyReifier do: [:ex | self getObject: ex object. ex resume]] on: USMRSDBCurrentCommitManager do: [:ex | ex resume: self currentCommitManager]. The idea here is that the system will use the error handlers that are included with seaside by calling super withErrorHandler: [ But then you can include your own Errors to handle. Just subclass Exception to create your own exception and name it what ever you want. Then when you want to handle a special case, raise the exception from your code. For example in my code I could do this aCommitManager := USMRSDBCurrentCommitManager signal. This raises an exception unwinds the stack to this handler and then returns the currentCommitManager. It all works beautifully. Hope that helps!! Happy Coding, Ron Teitelbaum President / Principal Software Engineer US Medical Record Specialists [hidden email] > -----Original Message----- > From: C. David Shaffer > > In continuing the process of answering myself... > > I tried: > > > [ [1/0] ensure: [Transcript show: 'got it.'; cr]. > Transcript show: 'should not get here.'; cr ] > on: Error > do: [:ex | |signalContext handlerContext| > signalContext := ex instVarNamed: #signalContext. > handlerContext := ex instVarNamed: #handlerContext. > signalContext unwindTo: handlerContext. > self halt] > > > Seems to work as expected ('got it' shows up in transcript before one > quits the debugger). So, I'm trying: > > ProductionErrorHandler>>handleError: ex > |signalContext handlerContext| > signalContext := ex instVarNamed: #signalContext. > handlerContext := ex instVarNamed: #handlerContext. > signalContext unwindTo: handlerContext. > WACurrentSession value returnResponse: (WAResponse document: self > document mimeType: 'text/html') > > > for a bit to see how it goes. If it seems right I'll embed it in > exception and avoid all the instVarNamed: stuff. This makes ensure: and > critical: release their resources since there is no hope of re-entering > their contexts. > > David > > _______________________________________________ > Seaside mailing list > [hidden email] > http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside _______________________________________________ Seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
Ron Teitelbaum wrote:
> Hi David, > > I'm not sure I really understand your question. There is a place in the > code for handling exceptions. If you make your own subclass of WASession > then you can implement something like this: > > withErrorHandler: aBlock > "override and extend the basic seaside exception handling" > > ^[[super withErrorHandler: [aBlock > on: USMRSDBObjectRegister do: [:ex | self registerObject: ex > object. ex resume]]] > on: USMRSDBProxyReifier do: [:ex | self getObject: ex > object. ex resume]] > on: USMRSDBCurrentCommitManager do: [:ex | ex resume: self > currentCommitManager]. > > > All of your handlers jump back into the signaling context (they are more like Notifications). There's no unwinding to be done. I'm talking about dealing with unexpected Errors. Let me spell out an example: MyComponent>>someCallbackMethod model doSomethingImportant now in my model MyModel>>doSomethingImportant [self useSomeResource. UnexpectedError signal] ensure: [self freeSomeResource] This ensure: block will never run unless UnexpectedError is handled and that handler block exits. This never happens if you use subclasses of WAErrorHandler to deal with errors...hence my unwindTo: attempt. Your example led me to: MySession>>withErrorHandler: aBlock ^super withErrorHandler: [aBlock on: Error do: [:ex | MyErrorLogger logError: ex]. self returnResponse: ...] Notice that in order to satisfy the requirement that the resource be freed the "self returnResponse:" must be outside the error handler so that the ensure: blocks gets invoked. I think this is much better than my previous approach. Thanks Ron! David _______________________________________________ Seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
You are welcome!
- Ron > -----Original Message----- > From: C. David Shaffer > > Ron Teitelbaum wrote: > > Hi David, > > > > I'm not sure I really understand your question. There is a place in the > > code for handling exceptions. If you make your own subclass of > WASession > > then you can implement something like this: > > > > withErrorHandler: aBlock > > "override and extend the basic seaside exception handling" > > > > ^[[super withErrorHandler: [aBlock > > on: USMRSDBObjectRegister do: [:ex | self registerObject: ex > > object. ex resume]]] > > on: USMRSDBProxyReifier do: [:ex | self getObject: ex > > object. ex resume]] > > on: USMRSDBCurrentCommitManager do: [:ex | ex resume: self > > currentCommitManager]. > > > > > > > Yes! I think that would be better...but with some minor differences. > All of your handlers jump back into the signaling context (they are more > like Notifications). There's no unwinding to be done. I'm talking > about dealing with unexpected Errors. Let me spell out an example: > > MyComponent>>someCallbackMethod > model doSomethingImportant > > now in my model > > MyModel>>doSomethingImportant > [self useSomeResource. UnexpectedError signal] ensure: [self > freeSomeResource] > > This ensure: block will never run unless UnexpectedError is handled and > that handler block exits. This never happens if you use subclasses of > WAErrorHandler to deal with errors...hence my unwindTo: attempt. Your > example led me to: > > MySession>>withErrorHandler: aBlock > ^super withErrorHandler: [aBlock on: Error do: [:ex | MyErrorLogger > logError: ex]. > self returnResponse: ...] > > Notice that in order to satisfy the requirement that the resource be > freed the "self returnResponse:" must be outside the error handler so > that the ensure: blocks gets invoked. I think this is much better than > my previous approach. Thanks Ron! > > David > > _______________________________________________ > Seaside mailing list > [hidden email] > http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside _______________________________________________ Seaside mailing list [hidden email] http://lists.squeakfoundation.org/cgi-bin/mailman/listinfo/seaside |
Free forum by Nabble | Edit this page |