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 sb.append(", maxAttempts=").append(maxAttempts); 124 sb.append(", multiplier=").append(multiplier); 125 sb.append("]"); 126 return sb.toString(); 127 } 128 129 // ***************************************** 130 // Builder 131 // ***************************************** 132 133 public static Builder builder() { 134 return new Builder(); 135 } 136 137 public static Builder builder(BackOff template) { 138 return new Builder().read(template); 139 } 140 141 /** 142 * A builder for {@link BackOff} 143 */ 144 public static final class Builder { 145 private Duration delay = BackOff.DEFAULT_DELAY; 146 private Duration maxDelay = BackOff.MAX_DURATION; 147 private Duration maxElapsedTime = BackOff.MAX_DURATION; 148 private Long maxAttempts = Long.MAX_VALUE; 149 private Double multiplier = BackOff.DEFAULT_MULTIPLIER; 150 151 /** 152 * Read values from the given {@link BackOff} 153 */ 154 public Builder read(BackOff template) { 155 delay = template.delay; 156 maxDelay = template.maxDelay; 157 maxElapsedTime = template.maxElapsedTime; 158 maxAttempts = template.maxAttempts; 159 multiplier = template.multiplier; 160 161 return this; 162 } 163 164 public Builder delay(Duration delay) { 165 this.delay = delay; 166 return this; 167 } 168 169 public Builder delay(long delay, TimeUnit unit) { 170 return delay(Duration.ofMillis(unit.toMillis(delay))); 171 } 172 173 public Builder delay(long delay) { 174 return delay(Duration.ofMillis(delay)); 175 } 176 177 public Builder maxDelay(Duration maxDelay) { 178 this.maxDelay = maxDelay; 179 return this; 180 } 181 182 public Builder maxDelay(long maxDelay, TimeUnit unit) { 183 return maxDelay(Duration.ofMillis(unit.toMillis(maxDelay))); 184 } 185 186 public Builder maxDelay(long maxDelay) { 187 return maxDelay(Duration.ofMillis(maxDelay)); 188 } 189 190 public Builder maxElapsedTime(Duration maxElapsedTime) { 191 this.maxElapsedTime = maxElapsedTime; 192 return this; 193 } 194 195 public Builder maxElapsedTime(long maxElapsedTime, TimeUnit unit) { 196 return maxElapsedTime(Duration.ofMillis(unit.toMillis(maxElapsedTime))); 197 } 198 199 public Builder maxElapsedTime(long maxElapsedTime) { 200 return maxElapsedTime(Duration.ofMillis(maxElapsedTime)); 201 } 202 203 public Builder maxAttempts(Long attempts) { 204 this.maxAttempts = attempts; 205 return this; 206 } 207 208 public Builder multiplier(Double multiplier) { 209 this.multiplier = multiplier; 210 return this; 211 } 212 213 /** 214 * Build a new instance of {@link BackOff} 215 */ 216 public BackOff build() { 217 return new BackOff(delay, maxDelay, maxElapsedTime, maxAttempts, multiplier); 218 } 219 } 220}