Задача, которую она решает: часто бывает так, что какой-то код может не выполниться успешно "без причины", и если такое происходит, нужно просто попытаться выполнить его еще несколько раз -- возможно, с различными паузами между попытками. Чаще всего такое бывает с кодом, который дергает какие-то внешние сервисы -- тут может быть куча временных/случайных причин для сбоев: временная перегрузка сети, временная неработоспособность сети, временная перегрузка сервиса, перезапуск сервиса... Какую-то степень устойчивости к этим факторам предоставляют сами протоколы (например, тот же TCP какие-то сетевые сбои обрабатывает незаметно для пользователя) но этой степени часто недостаточно для целей конкретного приложения.
Вот, собственно, задачу "стучаться пока не откроют" библиотека и выполняет. Что с ней можно делать:
- Задать код, который нужно выполнять "пока не получится" (==он завершится без исключений)
- Задать стратегию задержки (back off) между отдельными попытками. Есть библиотека простых стратегий (без задержки, фиксированная пауза, линейно растущая пауза, экспоненциально растущая пауза...) + билдер/dsl для их комбинации. Например:
Backoff .withExponentialGrowingDelay() .startingWithDelay( 1, TimeUnit.SECONDS ) .maxTryes( 5 ) .maxDelay( 10, TimeUnit.SECONDS ) .build()
- Задать "фатальные ошибки" -- т.е. при некотором классе ошибок дальнейшее продолжение попыток смысла не имеет. Например, если сервис выбросил исключение ConnectionTimeout -- имеет смысл попробовать еще разок позже, авось сеть заработает. Но если сервис выкинул IncorrectProtocolVersionException, то дальше пробовать смысла нет -- мы явно ломимся куда-то не туда
Пример использования (запрос по URL-у):
private static final String URL_TO_QUERY = "http://google.com/?q=Retryer"; public static String simpleQuery( final String urlString ) throws Exception { final URL url = new URL( urlString ); final InputStream is = url.openStream(); try { final InputStreamReader r = new InputStreamReader( is, "ISO-8859-1" ); try { return CharStreams.toString( r ); } finally { r.close(); } } finally { is.close(); } } .... public static String queryRetryableComplex( final String urlQuery ) throws Exception { return new Retryer().doRetryable( new IRetryableTask<String, Exception>() { public String execute( final int tryNo ) throws Exception { return simpleQuery( urlQuery ); } public boolean isFatalReason( final int tryNo, final Throwable reason ) { return (reason instanceof MalformedURLException); } }, Backoff .withExponentialGrowingDelay() .startingWithDelay( 1, TimeUnit.SECONDS ) .maxTryes( 5 ) .maxDelay( 10, TimeUnit.SECONDS ) .build() ); }
здесь мы будем пытаться запросить гугл с экспоненциально растущей задержкой, начиная с 1 секунды, но не более 10 секунд, и не более 5 раз подряд. При этом мы не будем повторять запрос если он выбросит MalformedURLException (какой смысл-то?).
С удовольствием послушаю всяческую ругань. Обещаю активно и интересно ругаться в ответ :)
Комментариев нет:
Отправить комментарий