From: Robert Klemme Date: 2004-08-25T00:55:41+09:00 Subject: Re: POLS - exception comparisons "Ara.T.Howard" schrieb im Newsbeitrag news:Pine.LNX.4.60.0408240831420.7569@harp.ngdc.noaa.gov... > > > what is the meaning of this? > > > jib:~ > cat a.rb > def method > raise 'foobar' > end > > errors = [] > > 2.times do > Thread.new do > begin > method > rescue => e > errors << e > end > end.join > end > > p errors > > p(errors[-2] == errors[-1]) > > p((errors[-2].class == errors[-1].class and > errors[-2].message == errors[-1].message and > errors[-2].backtrace == errors[-1].backtrace)) > > > jib:~ > ruby a.rb > [#, #] > false > true > > > i'm writing some code which must be fault tolerant: something like > > > def error_wrap errors = [], &block > begin > block.call errors > rescue => e > errors << e > if errors.size >= @fault_tolerance > raise > else > if errors.size == 1 or (errors.size >= 2 and errors[-2] != errors[-1]) > @logger.warn{ errors.last } > error_wrap errors, &block > end > end > end > end > > which runs a block of code, handling errors by logging them if it's a new > error (don't busy the log duplicate errors), eventually failing if too many > errors are seen. > > the problems is that > > errors[-2] != errors[-1] > > is always true. as the first bit of code shows, the '==' operator seems to be > implemented in a counter intuitive way. doesn't it make sense that exceptions > with the same class, message, and backtrace should be considered the same? > > looking briefly at error.c leads me to believe that it's Object#== used to > compare exceptions - does this make sense? I guess nooene ever bothered because exceptions are usually not stored somewhere. You just throw them, catch them and print them. But you usually don't put them in some kind of collection. You could solve this by either using your comparison code (that compares stack traces etc.) or you convert the error to a string and compare those. Some additional remarks about your implementation: - I'd put the exception only into the array if it's the first one of this type. Maybe you have good reasons to do it otherwise (to be able to later detect duplicates for example). - Recursion is inefficient to do what you want, rather use 'retry'. - Your method silently exits if it's a repeated error. IMHO that's a bad solution since the error goes totally unnoticed (it's not logged and not raised either). - I don't like the idea that the block receives the errors array, but that's probably needed to be able to react on this. So this would be my implementation of your method: def error_wrap errors = [], &block begin block.call errors rescue => e if errors.size >= @fault_tolerance raise elsif errors.empty? or errors[-1].backtrace != e.backtrace errors << e @logger.warn { e } end retry end end On the broader perspective, personally I don't think having a *general* mechanism that automatically retries code in case of an exception being thrown is a good idea: whether or not you can repeat the code totally depends on the code at hand and I'd guess that always repeating it is not generally a good idea. But then you might have multiple very similar pieces of code where it makes sense indeed to have some mechanism. Kind regards robert