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

org.jitsi.retry.RetryStrategy Maven / Gradle / Ivy

There is a newer version: 1.1-146-g96ed31f
Show newest version
/*
 * Copyright @ 2015 - present, 8x8 Inc
 *
 * 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 org.jitsi.retry;

import org.jitsi.utils.logging.*;

import java.util.concurrent.*;

/**
 * A retry strategy for doing some job. It allows to specify initial delay
 * before the task is started as well as retry delay. It will be executed as
 * long as the task Callable returns true. It is
 * also possible to configure whether the retries should be continued after
 * unexpected exception or not.
 * If we decide to not continue retries from outside the task
 * {@link RetryStrategy#cancel()} method will prevent from scheduling future
 * retries(but it will not interrupt currently executing one). Check with
 * {@link RetryStrategy#isCancelled()} to stop the operation in progress.
 *
 * See "RetryStrategyTest" for usage samples.
 *
 * @author Pawel Domas
 */
public class RetryStrategy
{
    /**
     * The logger
     */
    private final static Logger logger = Logger.getLogger(RetryStrategy.class);

    /**
     * Scheduled executor service used to schedule retry task.
     */
    private final ScheduledExecutorService executor;

    /**
     * RetryTask instance which describes the retry task and provides
     * things like retry interval and callable method to be executed.
     */
    private RetryTask task;

    /**
     * Future instance used to eventually cancel the retry task.
     */
    private ScheduledFuture future;

    /**
     * Inner class implementing Runnable that does additional
     * processing around Callable retry job.
     */
    private final TaskRunner taskRunner = new TaskRunner();


    /**
     * Creates new RetryStrategy instance that will use
     * ScheduledExecutorService with pool size of 1 thread to schedule
     * retry attempts.
     */
    public RetryStrategy()
    {
        this(Executors.newScheduledThreadPool(1));
    }

    /**
     * Creates new instance of RetryStrategy that will use given
     * ScheduledExecutorService to schedule retry attempts.
     *
     * @param retryExecutor ScheduledExecutorService that will be used
     *                      for scheduling retry attempts.
     *
     * @throws NullPointerException if given retryExecutor is
     *         null
     */
    public RetryStrategy(ScheduledExecutorService retryExecutor)
    {
        if (retryExecutor == null)
        {
            throw new NullPointerException("executor");
        }

        this.executor = retryExecutor;
    }

    /**
     * Cancels any future retry attempts. Currently running tasks are not
     * interrupted.
     */
    synchronized public void cancel()
    {
        if (future != null)
        {
            future.cancel(false);
            future = null;
        }

        task.setCancelled(true);
    }

    /**
     * Returns true if this retry strategy has been cancelled or
     * false otherwise.
     */
    synchronized public boolean isCancelled()
    {
        return task != null && task.isCancelled();
    }

    /**
     * Start given RetryTask that will be executed for the first time
     * after {@link RetryTask#getInitialDelay()}. After first execution next
     * retry attempts will be rescheduled as long as it's callable method
     * returns true or until ({@link #cancel()} is called.
     *
     * @param task the retry task to be employed by this retry strategy instance
     */
    synchronized public void runRetryingTask(final RetryTask task)
    {
        if (task == null)
            throw new NullPointerException("task");

        this.task = task;
        this.future
            = executor.schedule(
                    taskRunner,
                    task.getInitialDelay(),
                    TimeUnit.MILLISECONDS);
    }

    /**
     * Schedules new retry attempt if we d
     */
    synchronized private void scheduleRetry()
    {
        if (task == null || task.isCancelled())
            return;

        this.future
            =  executor.schedule(
                    taskRunner,
                    task.getRetryDelay(),
                    TimeUnit.MILLISECONDS);
    }

    /**
     * Some extra processing around running retry callable.
     */
    class TaskRunner implements Runnable
    {
        @Override
        public void run()
        {
            try
            {
                if (task.getCallable().call())
                    scheduleRetry();
            }
            catch (Exception e)
            {
                logger.error(e, e);

                if (task.willRetryAfterException())
                    scheduleRetry();
            }
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy