use of org.opensearch.search.asynchronous.context.state.AsynchronousSearchState.FAILED in project asynchronous-search by opensearch-project.
the class AsynchronousSearchService method updateKeepAliveAndGetContext.
/**
* If an active context is found, a permit is acquired from
* {@linkplain AsynchronousSearchContextPermits}
* and on acquisition of permit, a check is performed to see if response has been persisted in system index. If true, we update
* expiration in index. Else we update expiration field in {@linkplain AsynchronousSearchActiveContext}.
*
* @param id asynchronous search id
* @param keepAlive the new keep alive duration
* @param asynchronousSearchContextId asynchronous search context id
* @param user current user
* @param listener listener to invoke after updating expiration.
*/
public void updateKeepAliveAndGetContext(String id, TimeValue keepAlive, AsynchronousSearchContextId asynchronousSearchContextId, User user, ActionListener<AsynchronousSearchContext> listener) {
ActionListener<AsynchronousSearchContext> exceptionTranslationWrapper = getExceptionTranslationWrapper(id, listener);
validateKeepAlive(keepAlive);
long requestedExpirationTime = currentTimeSupplier.getAsLong() + keepAlive.getMillis();
// find an active context on this node if one exists
Optional<AsynchronousSearchActiveContext> asynchronousSearchContextOptional = asynchronousSearchActiveStore.getContext(asynchronousSearchContextId);
// for all other stages we don't really care much as those contexts are destined to be discarded
if (asynchronousSearchContextOptional.isPresent()) {
AsynchronousSearchActiveContext asynchronousSearchActiveContext = asynchronousSearchContextOptional.get();
asynchronousSearchActiveContext.acquireContextPermitIfRequired(wrap(releasable -> {
ActionListener<AsynchronousSearchContext> releasableActionListener = runAfter(exceptionTranslationWrapper, releasable::close);
// At this point it's possible that the response would have been persisted to system index
if (asynchronousSearchActiveContext.isAlive() == false && asynchronousSearchActiveContext.keepOnCompletion()) {
logger.debug("Updating persistence store after state is PERSISTED asynchronous search id [{}] " + "for updating context", asynchronousSearchActiveContext.getAsynchronousSearchId());
persistenceService.updateExpirationTime(id, requestedExpirationTime, user, wrap((actionResponse) -> releasableActionListener.onResponse(new AsynchronousSearchPersistenceContext(id, asynchronousSearchContextId, actionResponse, currentTimeSupplier, namedWriteableRegistry)), releasableActionListener::onFailure));
} else {
if (isUserValid(user, asynchronousSearchActiveContext.getUser())) {
logger.debug("Updating persistence store: NO as state is NOT PERSISTED yet asynchronous search id [{}] " + "for updating context", asynchronousSearchActiveContext.getAsynchronousSearchId());
asynchronousSearchActiveContext.setExpirationTimeMillis(requestedExpirationTime);
releasableActionListener.onResponse(asynchronousSearchActiveContext);
} else {
releasableActionListener.onFailure(new OpenSearchSecurityException("User doesn't have necessary roles to access the " + "asynchronous search with id " + id, RestStatus.FORBIDDEN));
}
}
}, exception -> {
Throwable cause = ExceptionsHelper.unwrapCause(exception);
if (cause instanceof TimeoutException) {
// this should ideally not happen. This would mean we couldn't acquire permits within the timeout
logger.debug(() -> new ParameterizedMessage("Failed to acquire permits for " + "asynchronous search id [{}] for updating context within timeout 5s", asynchronousSearchActiveContext.getAsynchronousSearchId()), exception);
listener.onFailure(new OpenSearchTimeoutException(id));
} else {
// best effort we try an update the doc if one exists
if (asynchronousSearchActiveContext.keepOnCompletion()) {
logger.debug("Updating persistence store after failing to acquire permits for asynchronous search id [{}] for " + "updating context with expiration time [{}]", asynchronousSearchActiveContext.getAsynchronousSearchId(), requestedExpirationTime);
persistenceService.updateExpirationTime(id, requestedExpirationTime, user, wrap((actionResponse) -> exceptionTranslationWrapper.onResponse(new AsynchronousSearchPersistenceContext(id, asynchronousSearchContextId, actionResponse, currentTimeSupplier, namedWriteableRegistry)), exceptionTranslationWrapper::onFailure));
} else {
exceptionTranslationWrapper.onFailure(new ResourceNotFoundException(asynchronousSearchActiveContext.getAsynchronousSearchId()));
}
}
}), TimeValue.timeValueSeconds(5), "update keep alive");
} else {
// try update the doc on the index assuming there exists one.
logger.debug("Updating persistence store after active context evicted for asynchronous search id [{}] " + "for updating context", id);
persistenceService.updateExpirationTime(id, requestedExpirationTime, user, wrap((actionResponse) -> exceptionTranslationWrapper.onResponse(new AsynchronousSearchPersistenceContext(id, asynchronousSearchContextId, actionResponse, currentTimeSupplier, namedWriteableRegistry)), exceptionTranslationWrapper::onFailure));
}
}
use of org.opensearch.search.asynchronous.context.state.AsynchronousSearchState.FAILED in project asynchronous-search by opensearch-project.
the class AsynchronousSearchService method initStateMachine.
private AsynchronousSearchStateMachine initStateMachine() {
AsynchronousSearchStateMachine stateMachine = new AsynchronousSearchStateMachine(EnumSet.allOf(AsynchronousSearchState.class), INIT, contextEventListener);
stateMachine.markTerminalStates(EnumSet.of(CLOSED));
stateMachine.registerTransition(new AsynchronousSearchTransition<>(INIT, RUNNING, (s, e) -> ((AsynchronousSearchActiveContext) e.asynchronousSearchContext()).setTask(e.getSearchTask()), (contextId, listener) -> listener.onContextRunning(contextId), SearchStartedEvent.class));
stateMachine.registerTransition(new AsynchronousSearchTransition<>(RUNNING, SUCCEEDED, (s, e) -> ((AsynchronousSearchActiveContext) e.asynchronousSearchContext()).processSearchResponse(e.getSearchResponse()), (contextId, listener) -> listener.onContextCompleted(contextId), SearchSuccessfulEvent.class));
stateMachine.registerTransition(new AsynchronousSearchTransition<>(RUNNING, FAILED, (s, e) -> ((AsynchronousSearchActiveContext) e.asynchronousSearchContext()).processSearchFailure(e.getException()), (contextId, listener) -> listener.onContextFailed(contextId), SearchFailureEvent.class));
stateMachine.registerTransition(new AsynchronousSearchTransition<>(SUCCEEDED, PERSISTING, (s, e) -> asynchronousSearchPostProcessor.persistResponse((AsynchronousSearchActiveContext) e.asynchronousSearchContext(), e.getAsynchronousSearchPersistenceModel()), (contextId, listener) -> {
}, BeginPersistEvent.class));
stateMachine.registerTransition(new AsynchronousSearchTransition<>(FAILED, PERSISTING, (s, e) -> asynchronousSearchPostProcessor.persistResponse((AsynchronousSearchActiveContext) e.asynchronousSearchContext(), e.getAsynchronousSearchPersistenceModel()), (contextId, listener) -> {
}, BeginPersistEvent.class));
stateMachine.registerTransition(new AsynchronousSearchTransition<>(PERSISTING, PERSIST_SUCCEEDED, (s, e) -> {
}, (contextId, listener) -> listener.onContextPersisted(contextId), SearchResponsePersistedEvent.class));
stateMachine.registerTransition(new AsynchronousSearchTransition<>(PERSISTING, PERSIST_FAILED, (s, e) -> {
}, (contextId, listener) -> listener.onContextPersistFailed(contextId), SearchResponsePersistFailedEvent.class));
stateMachine.registerTransition(new AsynchronousSearchTransition<>(RUNNING, CLOSED, (s, e) -> asynchronousSearchActiveStore.freeContext(e.asynchronousSearchContext().getContextId()), (contextId, listener) -> listener.onRunningContextDeleted(contextId), SearchDeletedEvent.class));
for (AsynchronousSearchState state : EnumSet.of(PERSISTING, PERSIST_SUCCEEDED, PERSIST_FAILED, SUCCEEDED, FAILED, INIT)) {
stateMachine.registerTransition(new AsynchronousSearchTransition<>(state, CLOSED, (s, e) -> asynchronousSearchActiveStore.freeContext(e.asynchronousSearchContext().getContextId()), (contextId, listener) -> listener.onContextDeleted(contextId), SearchDeletedEvent.class));
}
return stateMachine;
}
use of org.opensearch.search.asynchronous.context.state.AsynchronousSearchState.FAILED in project asynchronous-search by opensearch-project.
the class AsynchronousSearchService method cancelAndFreeActiveAndPersistedContext.
// We are skipping user check in this while deleting from the persisted layer
// as we have already checked for user in the present active context.
private void cancelAndFreeActiveAndPersistedContext(AsynchronousSearchActiveContext asynchronousSearchContext, ActionListener<Boolean> listener, User user) {
// if there are no context found to be cleaned up we throw a ResourceNotFoundException
AtomicReference<Releasable> releasableReference = new AtomicReference<>(() -> {
});
ActionListener<Boolean> releasableListener = runAfter(listener, releasableReference.get()::close);
GroupedActionListener<Boolean> groupedDeletionListener = new GroupedActionListener<>(wrap((responses) -> {
if (responses.stream().anyMatch(r -> r)) {
logger.debug("Free context for asynchronous search [{}] successful ", asynchronousSearchContext.getAsynchronousSearchId());
releasableListener.onResponse(true);
} else {
logger.debug("Freeing context, asynchronous search [{}] not found ", asynchronousSearchContext.getAsynchronousSearchId());
releasableListener.onFailure(new ResourceNotFoundException(asynchronousSearchContext.getAsynchronousSearchId()));
}
}, releasableListener::onFailure), 2);
// We get a true or a ResourceNotFound from persistence layer. We want to translate it to either a true/false or any other exception
// that should be surfaced up
ActionListener<Boolean> translatedListener = wrap(groupedDeletionListener::onResponse, (ex) -> {
if (ex instanceof ResourceNotFoundException) {
groupedDeletionListener.onResponse(false);
} else {
logger.debug(() -> new ParameterizedMessage("Translating exception, received for asynchronous search [{}]", asynchronousSearchContext.getAsynchronousSearchId()), ex);
groupedDeletionListener.onFailure(ex);
}
});
String triggeredBy = user != null ? (" by user [" + user + "]") : "";
String cancelTaskReason = "Delete asynchronous search [" + asynchronousSearchContext.getAsynchronousSearchId() + "] has been triggered" + triggeredBy + ". Attempting to cancel in-progress search task";
// Intent of the lock here is to disallow ongoing migration to system index
// as if that is underway we might end up creating a new document post a DELETE was executed
asynchronousSearchContext.acquireContextPermitIfRequired(wrap(releasable -> {
releasableReference.set(releasable);
if (asynchronousSearchContext.keepOnCompletion()) {
handleCancelTaskPermitAcquired(asynchronousSearchContext, groupedDeletionListener, cancelTaskReason);
logger.debug("Deleting asynchronous search id [{}] from system index ", asynchronousSearchContext.getAsynchronousSearchId());
persistenceService.deleteResponse(asynchronousSearchContext.getAsynchronousSearchId(), user, translatedListener);
} else {
// keep on completion is false. simply cancel task and clean up active context
handleCancelTaskPermitAcquired(asynchronousSearchContext, wrap(r -> {
if (r) {
releasableListener.onResponse(true);
} else {
releasableListener.onFailure(new ResourceNotFoundException(asynchronousSearchContext.getAsynchronousSearchId()));
}
}, releasableListener::onFailure), cancelTaskReason);
}
}, exception -> {
Throwable cause = ExceptionsHelper.unwrapCause(exception);
if (cause instanceof TimeoutException) {
// this should ideally not happen. This would mean we couldn't acquire permits within the timeout
logger.debug(() -> new ParameterizedMessage("Failed to acquire permits for " + "asynchronous search id [{}] for updating context within timeout 5s", asynchronousSearchContext.getAsynchronousSearchId()), exception);
listener.onFailure(new OpenSearchTimeoutException(asynchronousSearchContext.getAsynchronousSearchId()));
} else {
// best effort clean up with acknowledged as false
if (asynchronousSearchContext.keepOnCompletion()) {
handleCancelTaskPermitAcquisitionFailed(asynchronousSearchContext, groupedDeletionListener, cancelTaskReason, exception);
logger.debug("Deleting asynchronous search id [{}] from system index ", asynchronousSearchContext.getAsynchronousSearchId());
persistenceService.deleteResponse(asynchronousSearchContext.getAsynchronousSearchId(), user, translatedListener);
} else {
handleCancelTaskPermitAcquisitionFailed(asynchronousSearchContext, releasableListener, cancelTaskReason, exception);
}
}
}), TimeValue.timeValueSeconds(5), "free context");
}
Aggregations