Hi Igor,<div><br></div><div>    I get the idea but I does one really need on:fork: ?  Why not add Exception&gt;fork, a la Exception&gt;pass?  So one writes</div><div><br></div><div>[ self doSomething  ] on: Error do: [:ex | ex fork ].</div>
<div><br></div><div>and if you want to specify a handler function you pass in a block:</div><div><br></div><div><div><br></div><div>[ self doSomething  ] on: Error do: [:ex | ex fork: [block to handle error in another process here] ].</div>
<div><br></div><div>?</div><div><br></div><div>Further, re the finalization issue why are you so resistant to the tried-and-tested VW solution that&#39;s been in use for about a decade?</div><div><br></div><div>best,</div>
<div>Eliot</div><br><div class="gmail_quote">On Thu, May 19, 2011 at 3:56 AM, Igor Stasenko <span dir="ltr">&lt;<a href="mailto:siguctua@gmail.com">siguctua@gmail.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
Hello,<br>
<br>
if you remember , there was a discussion about how to solve<br>
efficiently a following problem:<br>
<br>
We have a critical processes running in system, which usually running<br>
an infinite loop and providing some service(s), which triggered<br>
periodically.<br>
A most common case is weak finalization. We need to ensure that<br>
finalization works, and if finalization of some object causing an<br>
error,<br>
it should not affect the finalization of the rest of object(s) nor<br>
affect the finalization process (like suspending it or terminating<br>
it).<br>
Also, in another discussion about Announcements, we found that same<br>
requirement actually should be fulfilled by Announcement framework: a<br>
delivery of a single announcement to some subscriber may fail,<br>
however regardless of such failure, other subscribers should be able<br>
to receive an announcement no matter what happen.<br>
<br>
There was a different solutions proposed, like finalizing a single<br>
object in separate, forked process,<br>
so even if it will fail with error, the rest of finalizers are not<br>
affected by this and finalization process continues to run normally.<br>
However its not very effective, because you paying the cost of forking<br>
process each time you need to finalize new object. There was an<br>
optimized solution,<br>
but nevertheless it doesn&#39;t changing the idea: perform a single item<br>
finalization in separate process.<br>
<br>
Another (a bit lame) approach is to simply swallow any errors, and<br>
while it provides guarantee that your critical process won&#39;t be<br>
terminated due to errors,<br>
at the same time, it makes impossible to detect and fix error(s),<br>
which of course should be taken care of to prevent them from appearing<br>
in future.<br>
<br>
So, my idea is to fork only if error happens.<br>
Add a new protocol to BlockClosure, which could allow us to handle<br>
errors in special manner:<br>
<br>
[ self doSomething  ] on: Error fork: [:ex | handle error here ].<br>
<br>
it is similar to #on:do: , except that in case of error, and error<br>
handler is invoked in separate forked process, while original process<br>
simply returns from closure activation with nil return value.<br>
But don&#39;t think that it is implemented as simple as:<br>
<br>
on: error fork: handleAction<br>
  ^ self on: error do: [:ex | [handleAction cull: ex ] fork ].<br>
<br>
it would be too easy and therefore useless. :)<br>
Because when you do it like that, a debugger window which opens an<br>
error, will not show you the stack contents which you wanna see.<br>
And then you will have to manually inspect the exception and then<br>
inspect an exception context and so on, in order to determine what<br>
caused error.<br>
<br>
What my implementation does, is actually splits the stack of current<br>
process and all contexts which are above #on:fork: method is going to<br>
forked process,<br>
while original process simply returns to sender of #on:fork: with nil<br>
return value.<br>
<br>
So, consider the original stack of a single process:<br>
<br>
a. &lt;bottom&gt;<br>
a. ...<br>
a. ... sender of #on:fork:<br>
b. &lt;#on:fork:&gt;<br>
b. #on:do:<br>
b. ...<br>
b. ...<br>
b. ...<br>
b. SomeError signal.<br>
b. ...<br>
b. ...<br>
b. error handler.<br>
<br>
then in case of exception, all contexts labeled by (a) are left in<br>
original process, and original process continues execution from sender<br>
of on:fork:,<br>
while contexts labeled by (b) is transferred to a newly forked process.<br>
<br>
In this way, if exception is unhandled (if you put &#39;ex pass&#39; there),<br>
the debugger will show a usual stack trace, as you normally see when<br>
error occurs, except that you don&#39;t see stack below #on:do: method<br>
(which is a context next to #on:fork:),<br>
but that&#39;s already enough information to determine what causing an<br>
error and even fix it and complete the action!<br>
<br>
So, we can have a cake (a fault-tolerant critical services) and eat it<br>
too (conveniently debug errors which could happen there), and without<br>
extra overhead.<br>
<br>
Please review my implementation. I tried it with could different<br>
exceptions and it works fine.<br>
However there could be some caveats. I tried it on Cog and it works fine.<br>
<br>
If there everything ok, then we can start using this method in<br>
finalization and in announcements, which will improve our systems<br>
stability and make it much easier to deal with errors there :)<br>
<font color="#888888"><br>
--<br>
Best regards,<br>
Igor Stasenko AKA sig.<br>
</font><br><br>
<br></blockquote></div><br></div>