/** * Convenience utility: creates a retry loop calling the given proc and retrying if needed * * @param client Zookeeper * @param proc procedure to call with retry * @param <T> return type * @return procedure result * @throws Exception any non-retriable errors */ public static <T> T callWithRetry(CuratorZookeeperClient client, Callable<T> proc) throws Exception { T result = null; RetryLoop retryLoop = client.newRetryLoop(); while (retryLoop.shouldContinue()) { try { client.internalBlockUntilConnectedOrTimedOut(); result = proc.call(); retryLoop.markComplete(); } catch (Exception e) { retryLoop.takeException(e); } } return result; }
private <DATA_TYPE> void handleBackgroundOperationException( OperationAndData<DATA_TYPE> operationAndData, Throwable e) { do { if ((operationAndData != null) && RetryLoop.isRetryException(e)) { if (!Boolean.getBoolean(DebugUtils.PROPERTY_DONT_LOG_CONNECTION_ISSUES)) { log.debug("Retry-able exception received", e); } if (client .getRetryPolicy() .allowRetry( operationAndData.getThenIncrementRetryCount(), operationAndData.getElapsedTimeMs(), operationAndData)) { if (!Boolean.getBoolean(DebugUtils.PROPERTY_DONT_LOG_CONNECTION_ISSUES)) { log.debug("Retrying operation"); } backgroundOperations.offer(operationAndData); break; } else { if (!Boolean.getBoolean(DebugUtils.PROPERTY_DONT_LOG_CONNECTION_ISSUES)) { log.debug("Retry policy did not allow retry"); } if (operationAndData.getErrorCallback() != null) { operationAndData.getErrorCallback().retriesExhausted(operationAndData); } } } logError("Background exception was not retry-able or retry gave up", e); } while (false); }
private void backgroundOperationsLoop() { AuthInfo auth = authInfo.getAndSet(null); if (auth != null) { try { client.getZooKeeper().addAuthInfo(auth.scheme, auth.auth); } catch (Exception e) { logError("addAuthInfo for background operation threw exception", e); return; } } while (!Thread.interrupted()) { OperationAndData<?> operationAndData; try { operationAndData = backgroundOperations.take(); if (debugListener != null) { debugListener.listen(operationAndData); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } performBackgroundOperation(operationAndData); } }
@Override public void start() { log.info("Starting"); if (!state.compareAndSet(CuratorFrameworkState.LATENT, CuratorFrameworkState.STARTED)) { IllegalStateException error = new IllegalStateException(); log.error("Cannot be started more than once", error); throw error; } try { connectionStateManager.start(); // ordering dependency - must be called before client.start() client.start(); executorService = Executors.newFixedThreadPool(2, threadFactory); // 1 for listeners, 1 for background ops executorService.submit( new Callable<Object>() { @Override public Object call() throws Exception { backgroundOperationsLoop(); return null; } }); } catch (Exception e) { handleBackgroundOperationException(null, e); } }
@SuppressWarnings({"ThrowableResultOfMethodCallIgnored"}) <DATA_TYPE> void processBackgroundOperation( OperationAndData<DATA_TYPE> operationAndData, CuratorEvent event) { boolean isInitialExecution = (event == null); if (isInitialExecution) { performBackgroundOperation(operationAndData); return; } boolean doQueueOperation = false; do { if (RetryLoop.shouldRetry(event.getResultCode())) { if (client .getRetryPolicy() .allowRetry( operationAndData.getThenIncrementRetryCount(), operationAndData.getElapsedTimeMs(), operationAndData)) { doQueueOperation = true; } else { if (operationAndData.getErrorCallback() != null) { operationAndData.getErrorCallback().retriesExhausted(operationAndData); } KeeperException.Code code = KeeperException.Code.get(event.getResultCode()); Exception e = null; try { e = (code != null) ? KeeperException.create(code) : null; } catch (Throwable ignore) { } if (e == null) { e = new Exception("Unknown result code: " + event.getResultCode()); } logError("Background operation retry gave up", e); } break; } if (operationAndData.getCallback() != null) { sendToBackgroundCallback(operationAndData, event); break; } processEvent(event); } while (false); if (doQueueOperation) { queueOperation(operationAndData); } }
@Override public void close() { log.debug("Closing"); if (state.compareAndSet(CuratorFrameworkState.STARTED, CuratorFrameworkState.STOPPED)) { listeners.forEach( new Function<CuratorListener, Void>() { @Override public Void apply(CuratorListener listener) { CuratorEvent event = new CuratorEventImpl( CuratorFrameworkImpl.this, CuratorEventType.CLOSING, 0, null, null, null, null, null, null, null, null); try { listener.eventReceived(CuratorFrameworkImpl.this, event); } catch (Exception e) { log.error("Exception while sending Closing event", e); } return null; } }); listeners.clear(); unhandledErrorListeners.clear(); connectionStateManager.close(); client.close(); namespaceWatcherMap.close(); executorService.shutdownNow(); } }
ZooKeeper getZooKeeper() throws Exception { return client.getZooKeeper(); }
RetryLoop newRetryLoop() { return client.newRetryLoop(); }