0

I have the following class:

class WidgetClient {
    List<Widget> getAllWidgets() {
        _actuallyGetAllWidgets()
    }

    void saveWidget(Widget w) {
        _actuallySaveWidget(w)
    }

    void deleteWidget(Widget w) {
        _actaullyDeleteWidget(w)
    }
}

This class is a client access class for a Widget Service. Unfortunately the Widget Service is not very reliable and, for reasons I can't explain, without any sort of reproducibility, is intermittently unavailable. Any time my code executes one of the WidgetClient methods (hence invoking the remote Widget Service), I would like to retry up to 5 times if the invocation produces a WidgetServiceMethodUnavailableException. Now I could do this the non-Groovy way like so:

List<Widget> getAllWidgets() {
    int maxRetries = 5
    int currRetries = 0

    while(currRetries <= maxRetries) {
        currRetries++

        try {
            return _actuallyGetAllWidgets()
        } catch(WidgetServiceMethodUnavailableException wsmuExc) {
            continue
        } catch(Throwable t) {
            throw t
        }
    }
}

But that is nasty and worse yet, I need to add that code for each method inside the WidgetClient. I'd like to see if I could define a closure where this retry logic is stored, and then somehow invoke that closure from inside each WidgetClient method. Something like:

def faultTolerant = { Closure<T> method ->
    int maxRetries = 5
    int currRetries = 0

    while(currRetries <= maxRetries) {
        currRetries++

        try {
            return method()
        } catch(WidgetServiceMethodUnavailableException wsmuExc) {
            continue
        } catch(Throwable t) {
            throw t
        }
    }
}

Now my WidgetClient can look like:

class WidgetClient {
    List<Widget> getAllWidgets() {
        faultTolerant(_actuallyGetAllWidgets())
    }

    void saveWidget(Widget w) {
        faultTolerant(_actuallySaveWidget(w))
    }

    void deleteWidget(Widget w) {
        faultTolerant(_actaullyDeleteWidget(w))
    }
}

However, having never written my own Groovy closure before, I have no idea where to start. Any ideas?

smeeb
  • 27,777
  • 57
  • 250
  • 447
  • at first glance: would't that basically be working, if you would write `faultTolerant{_actuallyGetAllWidgets()}` etc. instead ? – cfrick Feb 24 '15 at 19:48
  • Does `List getAllWidgets() { faultTolerant {-> _actuallyGetAllWidgets()} }` do it? Not sure I totally get the question – tim_yates Feb 24 '15 at 19:49
  • 1
    Is `_actuallyGetAllWidgets()` etc a closure or a method? If they're closures then what you've posted should work. – jk47 Feb 25 '15 at 15:32
  • Thanks @jk47 (+1) - `_actuallyGetAllWidgets` is a **method**, any new thoughts? – smeeb Feb 27 '15 at 14:14
  • You can't pass methods to the faultTolerant method as it accepts closures. Change the methods to closures and it should work. – jk47 Feb 28 '15 at 11:44

1 Answers1

0

Your code looks good, all you need to do is pass closures to the faultTolerant() method which call the methods you need:

  class WidgetClient {
    List<Widget> getAllWidgets() {
        faultTolerant{_actuallyGetAllWidgets()}
    }

    void saveWidget(Widget w) {
        faultTolerant{_actuallySaveWidget(w)}
    }

    void deleteWidget(Widget w) {
        faultTolerant{_actaullyDeleteWidget(w)}
    }
}

As your faultTolerant method takes a Closure as the final parameter, you can call it as I have shown in the code above, and this will pass the given closure (which simply calls your actually*Widget() methods) to the faultTolerantmethod.

jk47
  • 755
  • 4
  • 10