All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.yahoo.elide.async.service.AsyncExecutorService Maven / Gradle / Ivy

There is a newer version: 7.1.2
Show newest version
/*
 * Copyright 2020, Yahoo Inc.
 * Licensed under the Apache License, Version 2.0
 * See LICENSE file in project root for terms.
 */
package com.yahoo.elide.async.service;

import com.yahoo.elide.Elide;
import com.yahoo.elide.async.models.AsyncApi;
import com.yahoo.elide.async.models.AsyncApiResult;
import com.yahoo.elide.async.models.QueryStatus;
import com.yahoo.elide.async.operation.AsyncApiUpdateOperation;
import com.yahoo.elide.async.service.dao.AsyncApiDao;
import com.yahoo.elide.core.security.User;
import com.yahoo.elide.graphql.QueryRunner;
import com.yahoo.elide.jsonapi.JsonApi;

import graphql.execution.DataFetcherExceptionHandler;
import graphql.execution.SimpleDataFetcherExceptionHandler;
import jakarta.inject.Inject;
import lombok.Data;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

/**
 * Service to execute Async queries.
 * It will schedule task to track long running queries and kills them.
 * It will also schedule task to update orphan query statuses after
 * host/app crash or restart.
 */
@Getter
@Slf4j
public class AsyncExecutorService {

    public static final int DEFAULT_THREAD_POOL_SIZE = 6;

    private Elide elide;
    private JsonApi jsonApi;
    private Map runners;
    private ExecutorService executor;
    private ExecutorService updater;
    private AsyncApiDao asyncApiDao;
    private ThreadLocal asyncResultFutureThreadLocal = new ThreadLocal<>();

    /**
     * A Future with Synchronous Execution Complete Flag.
     */
    @Data
    private static class AsyncApiResultFuture {
        private Future asyncFuture;
        private boolean synchronousTimeout = false;
    }

    @Inject
    public AsyncExecutorService(Elide elide, ExecutorService executor, ExecutorService updater, AsyncApiDao asyncApiDao,
            Optional optionalDataFetcherExceptionHandler) {
        this.elide = elide;
        runners = new HashMap<>();

        for (String apiVersion : elide.getElideSettings().getEntityDictionary().getApiVersions()) {
            runners.put(apiVersion, new QueryRunner(elide, apiVersion,
                    optionalDataFetcherExceptionHandler.orElseGet(SimpleDataFetcherExceptionHandler::new)));
        }

        this.jsonApi = new JsonApi(this.elide);
        this.executor = executor;
        this.updater = updater;
        this.asyncApiDao = asyncApiDao;
    }

    /**
     * Execute Query asynchronously.
     * @param queryObj Query Object
     * @param callable A Callabale implementation to execute in background.
     */
    public void executeQuery(AsyncApi queryObj, Callable callable) {
        AsyncApiResultFuture resultFuture = new AsyncApiResultFuture();
        try {
            Future asyncExecuteFuture = executor.submit(callable);
            resultFuture.setAsyncFuture(asyncExecuteFuture);
            queryObj.setStatus(QueryStatus.PROCESSING);
            AsyncApiResult queryResultObj = asyncExecuteFuture.get(queryObj.getAsyncAfterSeconds(), TimeUnit.SECONDS);
            queryObj.setResult(queryResultObj);
            queryObj.setStatus(QueryStatus.COMPLETE);
            queryObj.setUpdatedOn(new Date());
        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            log.error("InterruptedException: {}", e.toString());
            queryObj.setStatus(QueryStatus.FAILURE);
        } catch (ExecutionException e) {
            log.error("ExecutionException: {}", e.toString());
            queryObj.setStatus(QueryStatus.FAILURE);
        } catch (TimeoutException e) {
            log.error("TimeoutException: {}", e.toString());
            resultFuture.setSynchronousTimeout(true);
        } catch (Exception e) {
            log.error("Exception: {}", e.toString());
            queryObj.setStatus(QueryStatus.FAILURE);
        } finally {
            asyncResultFutureThreadLocal.set(resultFuture);
        }

    }
    /**
     * Complete Query asynchronously.
     * @param query AsyncQuery
     * @param user User
     * @param apiVersion API Version
     */
    public void completeQuery(AsyncApi query, User user, String apiVersion) {
        AsyncApiResultFuture asyncApiResultFuture = asyncResultFutureThreadLocal.get();
        if (asyncApiResultFuture.isSynchronousTimeout()) {
            log.debug("Task has not completed");
            updater.execute(new AsyncApiUpdateOperation(elide, asyncApiResultFuture.getAsyncFuture(), query,
                    asyncApiDao));
            asyncResultFutureThreadLocal.remove();
        } else {
            log.debug("Task has completed");
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy