use of org.opensearch.search.asynchronous.context.active.AsynchronousSearchActiveContext in project asynchronous-search by opensearch-project.
the class AsynchronousSearchService method findContext.
/**
* Tries to find an {@linkplain AsynchronousSearchActiveContext}. If not found,
* queries the {@linkplain AsynchronousSearchPersistenceService} for a hit. If a response is found, it builds and returns an
* {@linkplain AsynchronousSearchPersistenceContext}, else throws
* {@linkplain ResourceNotFoundException}
*
* @param id The asynchronous search id
* @param asynchronousSearchContextId the Async search context id
* @param user current user
* @param listener to be invoked on finding an {@linkplain AsynchronousSearchContext}
*/
public void findContext(String id, AsynchronousSearchContextId asynchronousSearchContextId, User user, ActionListener<AsynchronousSearchContext> listener) {
ActionListener<AsynchronousSearchContext> exceptionTranslationListener = getExceptionTranslationWrapper(id, listener);
Optional<AsynchronousSearchActiveContext> optionalAsynchronousSearchActiveContext = asynchronousSearchActiveStore.getContext(asynchronousSearchContextId);
// so most likely a CLOSED context is stale
if (optionalAsynchronousSearchActiveContext.isPresent() && optionalAsynchronousSearchActiveContext.get().isAlive()) {
logger.debug("Active context is present for asynchronous search ID [{}]", id);
AsynchronousSearchActiveContext asynchronousSearchActiveContext = optionalAsynchronousSearchActiveContext.get();
if (isUserValid(user, asynchronousSearchActiveContext.getUser()) == false) {
logger.debug("Invalid user requesting GET active context for asynchronous search id {}", id);
exceptionTranslationListener.onFailure(new OpenSearchSecurityException("User doesn't have necessary roles to access the asynchronous search with id " + id, RestStatus.FORBIDDEN));
} else {
exceptionTranslationListener.onResponse(asynchronousSearchActiveContext);
}
} else {
logger.debug("Active context is not present for asynchronous search ID [{}]", id);
persistenceService.getResponse(id, user, wrap((persistenceModel) -> exceptionTranslationListener.onResponse(new AsynchronousSearchPersistenceContext(id, asynchronousSearchContextId, persistenceModel, currentTimeSupplier, namedWriteableRegistry)), ex -> {
logger.debug(() -> new ParameterizedMessage("Context not found for ID in the system index {}", id), ex);
exceptionTranslationListener.onFailure(ex);
}));
}
}
use of org.opensearch.search.asynchronous.context.active.AsynchronousSearchActiveContext 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.active.AsynchronousSearchActiveContext in project asynchronous-search by opensearch-project.
the class AsynchronousSearchService method createAndStoreContext.
/**
* Creates a new active asynchronous search for a newly submitted asynchronous search.
*
* @param request the SubmitAsynchronousSearchRequest
* @param relativeStartTimeMillis the relative start time of the search in millis
* @param user current user
* @param reduceContextBuilder the reference for the reduceContextBuilder
* @return the AsynchronousSearchContext for the submitted request
*/
public AsynchronousSearchContext createAndStoreContext(SubmitAsynchronousSearchRequest request, long relativeStartTimeMillis, Supplier<InternalAggregation.ReduceContextBuilder> reduceContextBuilder, User user) {
validateRequest(request);
AsynchronousSearchContextId asynchronousSearchContextId = new AsynchronousSearchContextId(UUIDs.base64UUID(), idGenerator.incrementAndGet());
contextEventListener.onNewContext(asynchronousSearchContextId);
AsynchronousSearchProgressListener progressActionListener = new AsynchronousSearchProgressListener(relativeStartTimeMillis, (response) -> asynchronousSearchPostProcessor.processSearchResponse(response, asynchronousSearchContextId), (e) -> asynchronousSearchPostProcessor.processSearchFailure(e, asynchronousSearchContextId), threadPool.executor(AsynchronousSearchPlugin.OPEN_DISTRO_ASYNC_SEARCH_GENERIC_THREAD_POOL_NAME), threadPool::relativeTimeInMillis, reduceContextBuilder);
AsynchronousSearchActiveContext asynchronousSearchContext = new AsynchronousSearchActiveContext(asynchronousSearchContextId, clusterService.localNode().getId(), request.getKeepAlive(), request.getKeepOnCompletion(), threadPool, currentTimeSupplier, progressActionListener, user, () -> persistSearchFailure);
asynchronousSearchActiveStore.putContext(asynchronousSearchContextId, asynchronousSearchContext, contextEventListener::onContextRejected);
contextEventListener.onContextInitialized(asynchronousSearchContextId);
return asynchronousSearchContext;
}
use of org.opensearch.search.asynchronous.context.active.AsynchronousSearchActiveContext 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.active.AsynchronousSearchActiveContext in project asynchronous-search by opensearch-project.
the class AsynchronousSearchSingleNodeTestCase method assertAsynchronousSearchResourceCleanUp.
protected void assertAsynchronousSearchResourceCleanUp(String id) {
assertDocNotPresentInAsynchronousSearchResponseIndex(id);
AsynchronousSearchService asService = getInstanceFromNode(AsynchronousSearchService.class);
Map<Long, AsynchronousSearchActiveContext> activeContexts = asService.getAllActiveContexts();
assertTrue(activeContexts.isEmpty());
}
Aggregations