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

com.watchrabbit.executor.command.ExecutorCommand Maven / Gradle / Ivy

/*
 * Copyright 2014 Mariusz.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.watchrabbit.executor.command;

import com.watchrabbit.commons.callback.CheckedConsumer;
import com.watchrabbit.executor.service.CommandService;
import com.watchrabbit.executor.service.CommandServiceImpl;
import com.watchrabbit.executor.wrapper.CacheConfig;
import com.watchrabbit.executor.wrapper.CheckedRunnable;
import com.watchrabbit.executor.wrapper.CommandConfig;
import com.watchrabbit.executor.wrapper.RetryConfig;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author Mariusz
 */
public class ExecutorCommand {

    private static final Logger LOGGER = LoggerFactory.getLogger(ExecutorCommand.class);

    private final CommandService service = new CommandServiceImpl();

    private final CommandConfig config;

    protected ExecutorCommand(CommandConfig config) {
        this.config = config;
    }

    /**
     * Adds cache logic to callable processing.
     *
     * @param cacheConfig cache configuration used by executor
     * @return {@code ExecutorCommand} executor with cache configuration
     */
    public ExecutorCommand withCache(CacheConfig cacheConfig) {
        config.setCacheConfig(cacheConfig);
        return this;
    }

    /**
     * Adds retry logic to callable processing.
     *
     * @param retryConfig retry configuration used by executor
     * @return {@code ExecutorCommand} executor with retry configuration
     */
    public ExecutorCommand withRetry(RetryConfig retryConfig) {
        config.setRetryConfig(retryConfig);
        return this;
    }

    /**
     * After {@code breakerRetryTimeout} elapses circuit breaker will
     * automatically close connection.
     *
     * @param breakerRetryTimeout timeout used by circuit
     * @param breakerRetryTimeUnit timeout time unit
     * @return {@code ExecutorCommand} executor with configured timeout
     */
    public ExecutorCommand withBreakerRetryTimeout(long breakerRetryTimeout, TimeUnit breakerRetryTimeUnit) {
        config.setBreakerRetryTimeout(breakerRetryTimeUnit.toMillis(breakerRetryTimeout));
        return this;
    }

    /**
     * If wrapped method throws one of passed exceptions breaker will pass it
     * without opening connection.
     *
     * @param excludedExceptions exceptions that should not open breaker
     * @return {@code ExecutorCommand} executor with configured
     * excludedExceptions
     */
    public ExecutorCommand withExcludedExceptions(List> excludedExceptions) {
        config.setExcludedExceptions(excludedExceptions);
        return this;
    }

    /**
     * Invokes runnable synchronously with respecting circuit logic and cache
     * logic if configured.
     *
     * @param runnable method fired by executor
     * @throws Exception if runnable throws some exception
     */
    public void invoke(CheckedRunnable runnable) throws Exception {
        invoke(()
                -> {
                    runnable.run();
                    return null;
                });
    }

    /**
     * Invokes callable synchronously with respecting circuit logic and cache
     * logic if configured.
     *
     * @param  type of value returned by this method
     * @param callable method fired by executor
     * @return {@code V} returns value returned by callable
     * @throws Exception if callable throws some exception
     */
    public  V invoke(Callable callable) throws Exception {
        return service.executeSynchronously(callable, config);
    }

    /**
     * Invokes runnable asynchronously with respecting circuit logic and cache
     * logic if configured.
     *
     * @param runnable method fired by executor
     */
    public void queue(CheckedRunnable runnable) {
        queue(()
                -> {
                    runnable.run();
                    return null;
                });
    }

    /**
     * Invokes runnable asynchronously with respecting circuit logic and cache
     * logic if configured.
     *
     * @param callable method fired by executor
     * @return {@code Future} with value or exception returned by callable
     */
    public Future queue(Callable callable) {
        return service.executeAsynchronously(callable, config);
    }

    /**
     * Invokes runnable asynchronously with respecting circuit logic and cache
     * logic if configured. If callable completed with success then the
     * {@code onSuccess} method is called.
     *
     * @param  type of returned value by callable
     * @param callable method fired by executor
     * @param onSuccess method fired if callable is completed with success
     */
    public  void observe(Callable callable, CheckedConsumer onSuccess) {
        service.executeAsynchronously(wrap(callable, onSuccess), config);
    }

    /**
     * Invokes runnable asynchronously with respecting circuit logic and cache
     * logic if configured. If callable completed with success then the
     * {@code onSuccess} method is called.
     *
     * @param runnable method fired by executor
     * @param onSuccess method fired if callable is completed with success
     */
    public void observe(CheckedRunnable runnable, CheckedRunnable onSuccess) {
        service.executeAsynchronously(wrap(runnable, onSuccess), config);
    }

    /**
     * Invokes runnable asynchronously with respecting circuit logic and cache
     * logic if configured. If callable completed with success then the
     * {@code onSuccess} method is called. If callable throws exception then
     * {@code onFailure} method is called
     *
     * @param  type of returned value by callable
     * @param callable method fired by executor
     * @param onSuccess method fired if callable is completed with success
     * @param onFailure method fired if callable throws
     */
    public  void observe(Callable callable, CheckedConsumer onSuccess, Consumer onFailure) {
        service.executeAsynchronously(wrap(callable, onSuccess, onFailure), config);
    }

    /**
     * Invokes runnable asynchronously with respecting circuit logic and cache
     * logic if configured. If callable completed with success then the
     * {@code onSuccess} method is called. If callable throws exception then
     * {@code onFailure} method is called
     *
     * @param runnable method fired by executor
     * @param onSuccess method fired if callable is completed with success
     * @param onFailure method fired if callable throws
     */
    public void observe(CheckedRunnable runnable, CheckedRunnable onSuccess, Consumer onFailure) {
        service.executeAsynchronously(wrap(runnable, onSuccess, onFailure), config);
    }

    private  Callable wrap(Callable callable, CheckedConsumer successConsumer) {
        return wrap(callable, successConsumer, (ex) -> LOGGER.debug("Exception thrown by observed callable", ex));
    }

    private  Callable wrap(CheckedRunnable runnable, CheckedRunnable onSuccess) {
        return wrap(runnable, onSuccess, (ex) -> LOGGER.debug("Exception thrown by observed callable", ex));
    }

    private  Callable wrap(CheckedRunnable runnable, CheckedRunnable onSuccess, Consumer errorConsumer) {
        return () -> {
            try {
                runnable.run();
                try {
                    onSuccess.run();
                } catch (Exception ex) {
                    LOGGER.debug("Suppress exception throwed by success callback", ex);
                }
            } catch (Exception ex) {
                errorConsumer.accept(ex);
            }
            return null;
        };
    }

    private  Callable wrap(Callable callable, CheckedConsumer successConsumer, Consumer errorConsumer) {
        return () -> {
            try {
                V result = callable.call();
                try {
                    successConsumer.accept(result);
                } catch (Exception ex) {
                    LOGGER.debug("Suppress exception throwed by success callback", ex);
                }
            } catch (Exception ex) {
                errorConsumer.accept(ex);
            }
            return null;
        };
    }

    /**
     * Enables exception suppressing mode.
     *
     * @return {@code SilentFailExecutorCommand} with exception suppressing
     */
    public SilentFailExecutorCommand silentFailMode() {
        return new SilentFailExecutorCommand<>(config);
    }

    /**
     * Creates new executor with circuit breaker with name {@code circuitName}
     * used to determine if circuit is closed or open by another executors.
     *
     * @param  type returned by callable methods
     * @param circuitName used to enable circuit breaker
     * @return {@code ExecutorCommand}
     */
    public static  ExecutorCommand executor(String circuitName) {
        CommandConfig commandConfig = new CommandConfig();
        commandConfig.setCommandName(circuitName);
        return new ExecutorCommand<>(commandConfig);
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy