001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.camel.util.backoff; 018 019import java.time.Duration; 020import java.util.concurrent.TimeUnit; 021 022import org.apache.camel.util.ObjectHelper; 023 024/** 025 * A back-off policy. 026 */ 027public final class BackOff { 028 public static final long NEVER = -1L; 029 public static final Duration MAX_DURATION = Duration.ofMillis(Long.MAX_VALUE); 030 public static final Duration DEFAULT_DELAY = Duration.ofSeconds(2); 031 public static final double DEFAULT_MULTIPLIER = 1f; 032 033 private Duration delay; 034 private Duration maxDelay; 035 private Duration maxElapsedTime; 036 private Long maxAttempts; 037 private Double multiplier; 038 039 public BackOff() { 040 this(DEFAULT_DELAY, MAX_DURATION, MAX_DURATION, Long.MAX_VALUE, DEFAULT_MULTIPLIER); 041 } 042 043 public BackOff(Duration delay, Duration maxDelay, Duration maxElapsedTime, Long maxAttempts, Double multiplier) { 044 this.delay = ObjectHelper.supplyIfEmpty(delay, () -> DEFAULT_DELAY); 045 this.maxDelay = ObjectHelper.supplyIfEmpty(maxDelay, () -> MAX_DURATION); 046 this.maxElapsedTime = ObjectHelper.supplyIfEmpty(maxElapsedTime, () -> MAX_DURATION); 047 this.maxAttempts = ObjectHelper.supplyIfEmpty(maxAttempts, () -> Long.MAX_VALUE); 048 this.multiplier = ObjectHelper.supplyIfEmpty(multiplier, () -> DEFAULT_MULTIPLIER); 049 } 050 051 // ************************************* 052 // Properties 053 // ************************************* 054 055 /** 056 * @return the delay to wait before retry the operation. 057 */ 058 public Duration getDelay() { 059 return delay; 060 } 061 062 /** 063 * The delay to wait before retry the operation. 064 */ 065 public void setDelay(Duration delay) { 066 this.delay = delay; 067 } 068 069 public Duration getMaxDelay() { 070 return maxDelay; 071 } 072 073 /** 074 * The maximum back-off time after which the delay is not more increased. 075 */ 076 public void setMaxDelay(Duration maxDelay) { 077 this.maxDelay = maxDelay; 078 } 079 080 public Duration getMaxElapsedTime() { 081 return maxElapsedTime; 082 } 083 084 /** 085 * The maximum elapsed time after which the back-off should be considered 086 * exhausted and no more attempts should be made. 087 */ 088 public void setMaxElapsedTime(Duration maxElapsedTime) { 089 this.maxElapsedTime = maxElapsedTime; 090 } 091 092 public Long getMaxAttempts() { 093 return maxAttempts; 094 } 095 096 /** 097 * The maximum number of attempts after which the back-off should be considered 098 * exhausted and no more attempts should be made. 099 * 100 * @param maxAttempts 101 */ 102 public void setMaxAttempts(Long maxAttempts) { 103 this.maxAttempts = maxAttempts; 104 } 105 106 public Double getMultiplier() { 107 return multiplier; 108 } 109 110 /** 111 * The value to multiply the current interval by for each retry attempt. 112 */ 113 public void setMultiplier(Double multiplier) { 114 this.multiplier = multiplier; 115 } 116 117 @Override 118 public String toString() { 119 return "BackOff{" 120 + "delay=" + delay 121 + ", maxDelay=" + maxDelay 122 + ", maxElapsedTime=" + maxElapsedTime 123 + ", maxAttempts=" + maxAttempts 124 + ", multiplier=" + multiplier 125 + '}'; 126 } 127 128 // ***************************************** 129 // Builder 130 // ***************************************** 131 132 public static Builder builder() { 133 return new Builder(); 134 } 135 136 public static Builder builder(BackOff template) { 137 return new Builder().read(template); 138 } 139 140 /** 141 * A builder for {@link BackOff} 142 */ 143 public static final class Builder { 144 private Duration delay = BackOff.DEFAULT_DELAY; 145 private Duration maxDelay = BackOff.MAX_DURATION; 146 private Duration maxElapsedTime = BackOff.MAX_DURATION; 147 private Long maxAttempts = Long.MAX_VALUE; 148 private Double multiplier = BackOff.DEFAULT_MULTIPLIER; 149 150 /** 151 * Read values from the given {@link BackOff} 152 */ 153 public Builder read(BackOff template) { 154 delay = template.delay; 155 maxDelay = template.maxDelay; 156 maxElapsedTime = template.maxElapsedTime; 157 maxAttempts = template.maxAttempts; 158 multiplier = template.multiplier; 159 160 return this; 161 } 162 163 public Builder delay(Duration delay) { 164 this.delay = delay; 165 return this; 166 } 167 168 public Builder delay(long delay, TimeUnit unit) { 169 return delay(Duration.ofMillis(unit.toMillis(delay))); 170 } 171 172 public Builder delay(long delay) { 173 return delay(Duration.ofMillis(delay)); 174 } 175 176 public Builder maxDelay(Duration maxDelay) { 177 this.maxDelay = maxDelay; 178 return this; 179 } 180 181 public Builder maxDelay(long maxDelay, TimeUnit unit) { 182 return maxDelay(Duration.ofMillis(unit.toMillis(maxDelay))); 183 } 184 185 public Builder maxDelay(long maxDelay) { 186 return maxDelay(Duration.ofMillis(maxDelay)); 187 } 188 189 public Builder maxElapsedTime(Duration maxElapsedTime) { 190 this.maxElapsedTime = maxElapsedTime; 191 return this; 192 } 193 194 public Builder maxElapsedTime(long maxElapsedTime, TimeUnit unit) { 195 return maxElapsedTime(Duration.ofMillis(unit.toMillis(maxElapsedTime))); 196 } 197 198 public Builder maxElapsedTime(long maxElapsedTime) { 199 return maxElapsedTime(Duration.ofMillis(maxElapsedTime)); 200 } 201 202 public Builder maxAttempts(Long attempts) { 203 this.maxAttempts = attempts; 204 return this; 205 } 206 207 public Builder multiplier(Double multiplier) { 208 this.multiplier = multiplier; 209 return this; 210 } 211 212 /** 213 * Build a new instance of {@link BackOff} 214 */ 215 public BackOff build() { 216 return new BackOff(delay, maxDelay, maxElapsedTime, maxAttempts, multiplier); 217 } 218 } 219}