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

com.microsoft.applicationinsights.internal.channel.common.SenderThreadLocalBackOffData Maven / Gradle / Ivy

/*
 * ApplicationInsights-Java
 * Copyright (c) Microsoft Corporation
 * All rights reserved.
 *
 * MIT License
 * Permission is hereby granted, free of charge, to any person obtaining a copy of this
 * software and associated documentation files (the ""Software""), to deal in the Software
 * without restriction, including without limitation the rights to use, copy, modify, merge,
 * publish, distribute, sublicense, and/or sell copies of the Software, and to permit
 * persons to whom the Software is furnished to do so, subject to the following conditions:
 * The above copyright notice and this permission notice shall be included in all copies or
 * substantial portions of the Software.
 * THE SOFTWARE IS PROVIDED *AS IS*, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
 * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 * DEALINGS IN THE SOFTWARE.
 */

package com.microsoft.applicationinsights.internal.channel.common;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

import com.google.common.base.Preconditions;

/**
 * The class is responsible for managing the back-off policy of a Sender thread.
 *
 * To make sure the network part of the Channel works as expected, please make sure that:
 *
 * 1. The class is used by every Sending thread.
 * 2. Every time a send is done, the caller thread must report the outcome.
 * 3. The class should be 'attached' to a Sending thread, which should be the only one
 *    to access its 'backOff' method.
 *
 * Created by gupele on 2/9/2015.
 */
final class SenderThreadLocalBackOffData {
    private final ReentrantLock lock;
    private final Condition backOffCondition;
    private int currentBackOffIndex;
    private boolean instanceIsActive;
    private final long addMilliseconds;
    private final long[] backOffTimeoutsInMillis;

    /**
     * The constructor must get the {@link BackOffTimesPolicy} that will supply the needed back-off timeouts.
     * @param backOffTimeoutsInMillis The array of timeouts that will be used when the thread needs to back off.
     * @param addMilliseconds The amount of seconds that will be added to the 'large' intervals to distinct between sender threads.
     */
    public SenderThreadLocalBackOffData(long[] backOffTimeoutsInMillis, long addMilliseconds) {
        Preconditions.checkNotNull(backOffTimeoutsInMillis, "backOffTimeoutsInSeconds must be not null");
        Preconditions.checkArgument(backOffTimeoutsInMillis.length > 0, "backOffTimeoutsInSeconds must not be empty");
        Preconditions.checkArgument(addMilliseconds >= 0, "addSeconds must not be >= 0");

        currentBackOffIndex = -1;
        instanceIsActive = true;
        lock = new ReentrantLock();
        backOffCondition = lock.newCondition();
        this.backOffTimeoutsInMillis = backOffTimeoutsInMillis;
        this.addMilliseconds = addMilliseconds;
    }

    public boolean isTryingToSend() {
        return currentBackOffIndex != -1;
    }
    
    /**
     * This method should be called by the Sender thread when the
     * Transmission is considered as 'done sending', which means the
     * Sender either sent the Transmission successfully or wishes to abandon its sending
     */
    public void onDoneSending() {
        currentBackOffIndex = -1;
    }

    /**
     * The calling thread will be suspended for an amount of time that is
     * set in the 'backOffTimeoutsInSeconds' array by using its index 'currentBackOffIndex'.
     *
     * @return True if the thread completed the suspension time as expected, in which case
     *         the caller should re-try to send the Transmission.
     *         False, in which case the caller should 'abandon' this Transmission and move to the next one,
     *         if:
     *         1. The instance was marked as non-active before the thread started to wait.
     *         2. The thread was signaled to stop while was waiting.
     *         3. The thread was interrupted while was waiting.
     *         4. The thread has exhausted all the back-off timeouts
     */
    public boolean backOff() {
        try {
            lock.lock();
            ++currentBackOffIndex;
            if (currentBackOffIndex == backOffTimeoutsInMillis.length) {
                currentBackOffIndex = -1;

                // Exhausted the back-offs
                return false;
            }

            if (!instanceIsActive) {
               return false;
           }

            try {
                long millisecondsToWait = backOffTimeoutsInMillis[currentBackOffIndex];
                if (millisecondsToWait > BackOffTimesPolicy.MIN_TIME_TO_BACK_OFF_IN_MILLS) {
                    millisecondsToWait += addMilliseconds;
                }
                backOffCondition.await(millisecondsToWait, TimeUnit.MILLISECONDS);
                return instanceIsActive;
           } catch (InterruptedException e) {
               return false;
           }
       } finally {
           lock.unlock();
       }
   }
    
    /**
     * Increment the current back off amount or resets the counter if needed.
     * 

* This method does not block but instead provides the amount of time to sleep which can be used * in another method. * @return The number of milliseconds to sleep for. */ public long backOffTimerValue() { try { lock.lock(); ++currentBackOffIndex; if (currentBackOffIndex == backOffTimeoutsInMillis.length) { currentBackOffIndex = -1; // Exhausted the back-offs return -1; } if (!instanceIsActive) { return 0; } long millisecondsToWait = backOffTimeoutsInMillis[currentBackOffIndex]; if (millisecondsToWait > BackOffTimesPolicy.MIN_TIME_TO_BACK_OFF_IN_MILLS) { millisecondsToWait += addMilliseconds; } return millisecondsToWait; } finally { lock.unlock(); } } /** * Stop a waiting thread if there is one, and prevent that thread for backOffing. */ public void stop() { try { lock.lock(); instanceIsActive = false; backOffCondition.signal(); } finally { lock.unlock(); } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy