/** * Key of the {@link HystrixCollapser} used for properties, metrics, caches, reporting etc. * * @return {@link HystrixCollapserKey} identifying this {@link HystrixCollapser} instance */ public HystrixCollapserKey getCollapserKey() { return collapserFactory.getCollapserKey(); }
/** * Construct a {@link HystrixObservableCollapser} with defined {@link Setter} that allows * injecting property and strategy overrides and other optional arguments. * <p> * Null values will result in the default being used. * * @param setter * Fluent interface for constructor arguments */ protected HystrixObservableCollapser(Setter setter) { this(setter.collapserKey, setter.scope, new RealCollapserTimer(), setter.propertiesSetter, null); }
/** * Clears all state. If new requests come in instances will be recreated and metrics started from scratch. */ /* package */static void reset() { RequestCollapserFactory.reset(); }
public RequestCollapser<BatchReturnType, ResponseType, RequestArgumentType> getRequestCollapser(HystrixCollapserBridge<BatchReturnType, ResponseType, RequestArgumentType> commandCollapser) { if (Scopes.REQUEST == Scopes.valueOf(getScope().name())) { return getCollapserForUserRequest(commandCollapser); } else if (Scopes.GLOBAL == Scopes.valueOf(getScope().name())) { return getCollapserForGlobalScope(commandCollapser); } else { logger.warn("Invalid Scope: {} Defaulting to REQUEST scope.", getScope()); return getCollapserForUserRequest(commandCollapser); } }
/** * Scope of collapsing. * <p> * <ul> * <li>REQUEST: Requests within the scope of a {@link HystrixRequestContext} will be collapsed. * <p> * Typically this means that requests within a single user-request (ie. HTTP request) are collapsed. No interaction with other user requests. 1 queue per user request. * </li> * <li>GLOBAL: Requests from any thread (ie. all HTTP requests) within the JVM will be collapsed. 1 queue for entire app.</li> * </ul> * <p> * Default: {@link Scope#REQUEST} (defined via constructor) * * @return {@link Scope} that collapsing should be performed within. */ public Scope getScope() { return Scope.valueOf(collapserFactory.getScope().name()); }
/** * Set an ISE if a response is not yet received otherwise skip it * * @param e A pre-generated exception. If this is null an ISE will be created and returned * @param exceptionMessage The message for the ISE */ public Exception setExceptionIfResponseNotReceived(Exception e, String exceptionMessage) { Exception exception = e; if (!valueSet.get() && !isTerminated()) { if (e == null) { exception = new IllegalStateException(exceptionMessage); } setExceptionIfResponseNotReceived(exception); } // return any exception that was generated return exception; }
/** * Lookup (or create and store) the RequestVariable for a given HystrixCollapserKey. * * @param commandCollapser collapser to retrieve {@link HystrixRequestVariableHolder} for * @return HystrixRequestVariableHolder */ @SuppressWarnings("unchecked") private HystrixRequestVariableHolder<RequestCollapser<?, ?, ?>> getRequestVariableForCommand(final HystrixCollapserBridge<BatchReturnType, ResponseType, RequestArgumentType> commandCollapser) { HystrixRequestVariableHolder<RequestCollapser<?, ?, ?>> requestVariable = requestScopedCollapsers.get(commandCollapser.getCollapserKey().name()); if (requestVariable == null) { // create new collapser using 'this' first instance as the one that will get cached for future executions ('this' is stateless so we can do that) @SuppressWarnings({ "rawtypes" }) HystrixRequestVariableHolder newCollapser = new RequestCollapserRequestVariable(commandCollapser, properties, timer, concurrencyStrategy); HystrixRequestVariableHolder<RequestCollapser<?, ?, ?>> existing = requestScopedCollapsers.putIfAbsent(commandCollapser.getCollapserKey().name(), newCollapser); if (existing == null) { // this thread won, so return the one we just created requestVariable = newCollapser; } else { // another thread beat us (this should only happen when we have concurrency on the FIRST request for the life of the app for this HystrixCollapser class) requestVariable = existing; /* * This *should* be okay to discard the created object without cleanup as the RequestVariable implementation * should properly do lazy-initialization and only call initialValue() the first time get() is called. * * If it does not correctly follow this contract then there is a chance of a memory leak here. */ } } return requestVariable; }
@Override public void setComplete() { if (!isTerminated()) { subject.onCompleted(); } }
private HystrixCollapserProperties getProperties() { return collapserFactory.getProperties(); }
/** * This handles failed completions */ @Override public void call(Throwable e) { // handle Throwable in case anything is thrown so we don't block Observers waiting for onError/onCompleted Exception ee; if (e instanceof Exception) { ee = (Exception) e; } else { ee = new RuntimeException("Throwable caught while executing batch and mapping responses.", e); } logger.debug("Exception mapping responses to requests.", e); // if a failure occurs we want to pass that exception to all of the Futures that we've returned for (CollapsedRequest<ResponseType, RequestArgumentType> request : argumentMap.values()) { try { ((CollapsedRequestSubject<ResponseType, RequestArgumentType>) request).setExceptionIfResponseNotReceived(ee); } catch (IllegalStateException e2) { // if we have partial responses set in mapResponseToRequests // then we may get IllegalStateException as we loop over them // so we'll log but continue to the rest logger.error("Partial success of 'mapResponseToRequests' resulted in IllegalStateException while setting Exception. Continuing ... ", e2); } } }
@SuppressWarnings("unchecked") private RequestCollapser<BatchReturnType, ResponseType, RequestArgumentType> getCollapserForUserRequest(HystrixCollapserBridge<BatchReturnType, ResponseType, RequestArgumentType> commandCollapser) { return (RequestCollapser<BatchReturnType, ResponseType, RequestArgumentType>) getRequestVariableForCommand(commandCollapser).get(concurrencyStrategy); }
/** * Called from RequestVariable.shutdown() to unschedule the task. */ public void shutdown() { RequestBatch<BatchReturnType, ResponseType, RequestArgumentType> currentBatch = batch.getAndSet(null); if (currentBatch != null) { currentBatch.shutdown(); } if (timerListenerReference.get() != null) { // if the timer was started we'll clear it so it stops ticking timerListenerReference.get().clear(); } }
/** * Scope of collapsing. * <p> * <ul> * <li>REQUEST: Requests within the scope of a {@link HystrixRequestContext} will be collapsed. * <p> * Typically this means that requests within a single user-request (ie. HTTP request) are collapsed. No interaction with other user requests. 1 queue per user request. * </li> * <li>GLOBAL: Requests from any thread (ie. all HTTP requests) within the JVM will be collapsed. 1 queue for entire app.</li> * </ul> * <p> * Default: {@link Scope#REQUEST} (defined via constructor) * * @return {@link Scope} that collapsing should be performed within. */ public Scope getScope() { return Scope.valueOf(collapserFactory.getScope().name()); }
/** * Construct a {@link HystrixCollapser} with defined {@link Setter} that allows * injecting property and strategy overrides and other optional arguments. * <p> * Null values will result in the default being used. * * @param setter * Fluent interface for constructor arguments */ protected HystrixCollapser(Setter setter) { this(setter.collapserKey, setter.scope, new RealCollapserTimer(), setter.propertiesSetter, null); }
/** * Set an exception if a response is not yet received otherwise skip it * * @param e synthetic error to set on initial command when no actual response is available */ public void setExceptionIfResponseNotReceived(Exception e) { if (!valueSet.get() && !isTerminated()) { subject.onError(e); } }
/** * Key of the {@link HystrixObservableCollapser} used for properties, metrics, caches, reporting etc. * * @return {@link HystrixCollapserKey} identifying this {@link HystrixObservableCollapser} instance */ public HystrixCollapserKey getCollapserKey() { return collapserFactory.getCollapserKey(); }
/** * Clears all state. If new requests come in instances will be recreated and metrics started from scratch. */ /* package */static void reset() { RequestCollapserFactory.reset(); }
private HystrixCollapserProperties getProperties() { return collapserFactory.getProperties(); }
/** * When set any client thread blocking on get() will immediately be unblocked and receive the exception. * * @throws IllegalStateException * if called more than once or after setResponse. * @param e received exception that gets set on the initial command */ @Override public void setException(Exception e) { if (!isTerminated()) { subject.onError(e); } else { throw new IllegalStateException("Response has already terminated so exception can not be set", e); } }
/** * Emit a response that should be OnNexted to an Observer * @param response response to emit to initial command */ @Override public void emitResponse(T response) { if (!isTerminated()) { subject.onNext(response); valueSet.set(true); } else { throw new IllegalStateException("Response has already terminated so response can not be set : " + response); } }