]> git.basschouten.com Git - openhab-addons.git/blob
849b3772335636edb71e31a55bb7aa4797466c3f
[openhab-addons.git] /
1 /**
2  * Copyright (c) 2010-2023 Contributors to the openHAB project
3  *
4  * See the NOTICE file(s) distributed with this work for additional
5  * information.
6  *
7  * This program and the accompanying materials are made available under the
8  * terms of the Eclipse Public License 2.0 which is available at
9  * http://www.eclipse.org/legal/epl-2.0
10  *
11  * SPDX-License-Identifier: EPL-2.0
12  */
13 package org.openhab.binding.mielecloud.internal.webservice.sse;
14
15 import java.util.Random;
16
17 import org.eclipse.jdt.annotation.NonNullByDefault;
18 import org.slf4j.Logger;
19 import org.slf4j.LoggerFactory;
20
21 /**
22  * Implements the exponential backoff with jitter backoff strategy.
23  *
24  * @author Björn Lange - Initial contribution
25  */
26 @NonNullByDefault
27 class ExponentialBackoffWithJitter implements BackoffStrategy {
28     private static final long INITIAL_RECONNECT_ATTEMPT_WAIT_TIME_IN_SECONDS = 5;
29     private static final long MAXIMUM_RECONNECT_ATTEMPT_WAIT_TIME_IN_SECONDS = 3600;
30
31     private final long minimumWaitTimeInSeconds;
32     private final long maximumWaitTimeInSeconds;
33     private final long retryIntervalInSeconds;
34     private final Random random;
35
36     private final Logger logger = LoggerFactory.getLogger(ExponentialBackoffWithJitter.class);
37
38     /**
39      * Creates a new {@link ExponentialBackoffWithJitter}.
40      */
41     public ExponentialBackoffWithJitter() {
42         this(INITIAL_RECONNECT_ATTEMPT_WAIT_TIME_IN_SECONDS, MAXIMUM_RECONNECT_ATTEMPT_WAIT_TIME_IN_SECONDS,
43                 INITIAL_RECONNECT_ATTEMPT_WAIT_TIME_IN_SECONDS);
44     }
45
46     ExponentialBackoffWithJitter(long minimumWaitTimeInSeconds, long maximumWaitTimeInSeconds,
47             long retryIntervalInSeconds) {
48         this(minimumWaitTimeInSeconds, maximumWaitTimeInSeconds, retryIntervalInSeconds, new Random());
49     }
50
51     ExponentialBackoffWithJitter(long minimumWaitTimeInSeconds, long maximumWaitTimeInSeconds,
52             long retryIntervalInSeconds, Random random) {
53         if (minimumWaitTimeInSeconds < 0) {
54             throw new IllegalArgumentException("minimumWaitTimeInSeconds must not be smaller than zero");
55         }
56         if (maximumWaitTimeInSeconds < 0) {
57             throw new IllegalArgumentException("maximumWaitTimeInSeconds must not be smaller than zero");
58         }
59         if (retryIntervalInSeconds < 0) {
60             throw new IllegalArgumentException("retryIntervalInSeconds must not be smaller than zero");
61         }
62         if (maximumWaitTimeInSeconds < minimumWaitTimeInSeconds) {
63             throw new IllegalArgumentException(
64                     "maximumWaitTimeInSeconds must not be smaller than minimumWaitTimeInSeconds");
65         }
66         if (maximumWaitTimeInSeconds < retryIntervalInSeconds) {
67             throw new IllegalArgumentException(
68                     "maximumWaitTimeInSeconds must not be smaller than retryIntervalInSeconds");
69         }
70
71         this.minimumWaitTimeInSeconds = minimumWaitTimeInSeconds;
72         this.maximumWaitTimeInSeconds = maximumWaitTimeInSeconds;
73         this.retryIntervalInSeconds = retryIntervalInSeconds;
74         this.random = random;
75     }
76
77     @Override
78     public long getMinimumSecondsUntilRetry() {
79         return minimumWaitTimeInSeconds;
80     }
81
82     @Override
83     public long getMaximumSecondsUntilRetry() {
84         return maximumWaitTimeInSeconds;
85     }
86
87     @Override
88     public long getSecondsUntilRetry(int failedAttempts) {
89         if (failedAttempts < 0) {
90             logger.warn("The number of failed attempts must not be smaller than zero, was {}.", failedAttempts);
91         }
92
93         return minimumWaitTimeInSeconds
94                 + getRandomLongWithUpperLimit(Math.min(maximumWaitTimeInSeconds - minimumWaitTimeInSeconds,
95                         retryIntervalInSeconds * (long) Math.pow(2, Math.max(0, failedAttempts))));
96     }
97
98     private long getRandomLongWithUpperLimit(long upperLimit) {
99         return Math.abs(random.nextLong()) % (upperLimit + 1);
100     }
101 }