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 public Duration getDelay() { 056 return delay; 057 } 058 059 /** 060 * The delay to wait before retry the operation. 061 */ 062 public void setDelay(Duration delay) { 063 this.delay = delay; 064 } 065 066 public Duration getMaxDelay() { 067 return maxDelay; 068 } 069 070 /** 071 * The maximum back-off time after which the delay is not more increased. 072 */ 073 public void setMaxDelay(Duration maxDelay) { 074 this.maxDelay = maxDelay; 075 } 076 077 public Duration getMaxElapsedTime() { 078 return maxElapsedTime; 079 } 080 081 /** 082 * The maximum elapsed time after which the back-off should be considered exhausted and no more attempts should be 083 * made. 084 */ 085 public void setMaxElapsedTime(Duration maxElapsedTime) { 086 this.maxElapsedTime = maxElapsedTime; 087 } 088 089 public Long getMaxAttempts() { 090 return maxAttempts; 091 } 092 093 /** 094 * The maximum number of attempts after which the back-off should be considered exhausted and no more attempts 095 * should be made. 096 */ 097 public void setMaxAttempts(Long maxAttempts) { 098 this.maxAttempts = maxAttempts; 099 } 100 101 public Double getMultiplier() { 102 return multiplier; 103 } 104 105 /** 106 * The value to multiply the current interval by for each retry attempt. 107 */ 108 public void setMultiplier(Double multiplier) { 109 this.multiplier = multiplier; 110 } 111 112 @Override 113 public String toString() { 114 StringBuilder sb = new StringBuilder(); 115 sb.append("BackOff["); 116 sb.append("delay=").append(delay.toMillis()); 117 if (maxDelay != MAX_DURATION) { 118 sb.append(", maxDelay=").append(maxDelay.toMillis()); 119 } 120 if (maxElapsedTime != MAX_DURATION) { 121 sb.append(", maxElapsedTime=").append(maxElapsedTime.toMillis()); 122 } 123 if (maxAttempts != Long.MAX_VALUE) { 124 sb.append(", maxAttempts=").append(maxAttempts); 125 } 126 if (multiplier != DEFAULT_MULTIPLIER) { 127 sb.append(", multiplier=").append(multiplier); 128 } 129 sb.append("]"); 130 return sb.toString(); 131 } 132 133 // ***************************************** 134 // Builder 135 // ***************************************** 136 137 public static Builder builder() { 138 return new Builder(); 139 } 140 141 public static Builder builder(BackOff template) { 142 return new Builder().read(template); 143 } 144 145 /** 146 * A builder for {@link BackOff} 147 */ 148 public static final class Builder { 149 private Duration delay = BackOff.DEFAULT_DELAY; 150 private Duration maxDelay = BackOff.MAX_DURATION; 151 private Duration maxElapsedTime = BackOff.MAX_DURATION; 152 private Long maxAttempts = Long.MAX_VALUE; 153 private Double multiplier = BackOff.DEFAULT_MULTIPLIER; 154 155 /** 156 * Read values from the given {@link BackOff} 157 */ 158 public Builder read(BackOff template) { 159 delay = template.delay; 160 maxDelay = template.maxDelay; 161 maxElapsedTime = template.maxElapsedTime; 162 maxAttempts = template.maxAttempts; 163 multiplier = template.multiplier; 164 165 return this; 166 } 167 168 public Builder delay(Duration delay) { 169 this.delay = delay; 170 return this; 171 } 172 173 public Builder delay(long delay, TimeUnit unit) { 174 return delay(Duration.ofMillis(unit.toMillis(delay))); 175 } 176 177 public Builder delay(long delay) { 178 return delay(Duration.ofMillis(delay)); 179 } 180 181 public Builder maxDelay(Duration maxDelay) { 182 this.maxDelay = maxDelay; 183 return this; 184 } 185 186 public Builder maxDelay(long maxDelay, TimeUnit unit) { 187 return maxDelay(Duration.ofMillis(unit.toMillis(maxDelay))); 188 } 189 190 public Builder maxDelay(long maxDelay) { 191 return maxDelay(Duration.ofMillis(maxDelay)); 192 } 193 194 public Builder maxElapsedTime(Duration maxElapsedTime) { 195 this.maxElapsedTime = maxElapsedTime; 196 return this; 197 } 198 199 public Builder maxElapsedTime(long maxElapsedTime, TimeUnit unit) { 200 return maxElapsedTime(Duration.ofMillis(unit.toMillis(maxElapsedTime))); 201 } 202 203 public Builder maxElapsedTime(long maxElapsedTime) { 204 return maxElapsedTime(Duration.ofMillis(maxElapsedTime)); 205 } 206 207 public Builder maxAttempts(Long attempts) { 208 this.maxAttempts = attempts; 209 return this; 210 } 211 212 public Builder multiplier(Double multiplier) { 213 this.multiplier = multiplier; 214 return this; 215 } 216 217 /** 218 * Build a new instance of {@link BackOff} 219 */ 220 public BackOff build() { 221 return new BackOff(delay, maxDelay, maxElapsedTime, maxAttempts, multiplier); 222 } 223 } 224}