Reputation: 849
Smalltalk supports retry exceptions by using on: retry method defining the behavior between retries. I want to implement retry behaviors consisting of two additional operations: delayInterval, maxAttempts
[ operations ]
on: Exception
maxAttempts: 10
delayInterval: 5 seconds
do: [ : e | Transcript show: 'Trying...'; cr ]
Is there any elegant way to do this?
Upvotes: 2
Views: 152
Reputation: 14868
Carlos's approach is fine, but the problem I see with it is that sends the #on:do:
message a number of times. This is not necessary thanks to the fact that Exceptions
understand the #retry
message. So, instead of enclosing everything in a loop, we can loop inside the handling block, like this:
BlockClosure >> on: aClass do: aBlock maxAttempts: anInteger
| counter |
counter := anInteger.
^self
on: aClass
do: [:ex | | result |
result := aBlock value: ex.
counter := counter - 1.
counter > 0 ifTrue:[ex retry].
ex return: result]
Note that there is no "syntactic" loop in this code. The flow of execution, however, will evaluate the receiving block again in virtue of the ex retry
message (without reaching the ex return: result
line). Only if the counter
reaches 0
the handler will "give up" and return the value of the exception block aBlock
.
This same idea can now be used to introduce a timeout:
on: aClass
do: aBlock
maxAttempts: anInteger
timeout: anotherInteger
| counter timeout |
counter := anInteger.
timeout := TimeStamp now asMilliseconds + anotherInteger "dialect dependent".
^self
on: aClass
do: [:ex | | result |
result := aBlock value: ex.
counter := counter - 1.
(counter > 0 and: [TimeStamp now asMilliseconds < timeout])
ifTrue: [ex retry].
ex return: result]
The same considerations apply here. The only difference is that the retry
condition also takes into account the timeout limit.
Upvotes: 5
Reputation: 948
on: exceptionClass maxAttempts: anInteger delayInterval: seconds do: aBlock
max := anInteger.
exception := false.
[ result := self on: exceptionClass do: [ :ex | aBlock value: ex. exception := true. max := max - 1 ].
exception and: [max > 0 ] ] whileTrue: [ exception := false ].
^result
"elegant" is arguable...
Upvotes: 1