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.time.temporal.TemporalUnit; 021import java.util.concurrent.TimeUnit; 022 023import org.apache.camel.util.ObjectHelper; 024 025/** 026 * A back-off policy. 027 */ 028public final class BackOff { 029 public static final long NEVER = -1L; 030 public static final Duration MAX_DURATION = Duration.ofMillis(Long.MAX_VALUE); 031 public static final Duration DEFAULT_DELAY = Duration.ofSeconds(2); 032 public static final double DEFAULT_MULTIPLIER = 1f; 033 034 private Duration delay; 035 private Duration maxDelay; 036 private Duration maxElapsedTime; 037 private Long maxAttempts; 038 private Double multiplier; 039 040 public BackOff() { 041 this(DEFAULT_DELAY, MAX_DURATION, MAX_DURATION, Long.MAX_VALUE, DEFAULT_MULTIPLIER); 042 } 043 044 public BackOff(Duration delay, Duration maxDelay, Duration maxElapsedTime, Long maxAttempts, Double multiplier) { 045 this.delay = ObjectHelper.supplyIfEmpty(delay, () -> DEFAULT_DELAY); 046 this.maxDelay = ObjectHelper.supplyIfEmpty(maxDelay, () -> MAX_DURATION); 047 this.maxElapsedTime = ObjectHelper.supplyIfEmpty(maxElapsedTime, () -> MAX_DURATION); 048 this.maxAttempts = ObjectHelper.supplyIfEmpty(maxAttempts, () -> Long.MAX_VALUE); 049 this.multiplier = ObjectHelper.supplyIfEmpty(multiplier, () -> DEFAULT_MULTIPLIER); 050 } 051 052 // ************************************* 053 // Properties 054 // ************************************* 055 056 public Duration getDelay() { 057 return delay; 058 } 059 060 /** 061 * The delay to wait before retry the operation. 062 */ 063 public void setDelay(Duration delay) { 064 this.delay = delay; 065 } 066 067 public Duration getMaxDelay() { 068 return maxDelay; 069 } 070 071 /** 072 * The maximum back-off time after which the delay is not more increased. 073 */ 074 public void setMaxDelay(Duration maxDelay) { 075 this.maxDelay = maxDelay; 076 } 077 078 public Duration getMaxElapsedTime() { 079 return maxElapsedTime; 080 } 081 082 /** 083 * The maximum elapsed time after which the back-off should be considered 084 * exhausted and no more attempts should be made. 085 */ 086 public void setMaxElapsedTime(Duration maxElapsedTime) { 087 this.maxElapsedTime = maxElapsedTime; 088 } 089 090 public Long getMaxAttempts() { 091 return maxAttempts; 092 } 093 094 /** 095 * The maximum number of attempts after which the back-off should be considered 096 * exhausted and no more attempts should be made. 097 */ 098 public void setMaxAttempts(Long maxAttempts) { 099 this.maxAttempts = maxAttempts; 100 } 101 102 public Double getMultiplier() { 103 return multiplier; 104 } 105 106 /** 107 * The value to multiply the current interval by for each retry attempt. 108 */ 109 public void setMultiplier(Double multiplier) { 110 this.multiplier = multiplier; 111 } 112 113 @Override 114 public String toString() { 115 return "BackOff[" 116 + "delay=" + delay.toMillis() 117 + ", maxDelay=" + (maxDelay != MAX_DURATION ? maxDelay.toMillis() : "") 118 + ", maxElapsedTime=" + (maxElapsedTime != MAX_DURATION ? maxElapsedTime.toMillis() : "") 119 + ", maxAttempts=" + maxAttempts 120 + ", multiplier=" + multiplier 121 + ']'; 122 } 123 124 // ***************************************** 125 // Builder 126 // ***************************************** 127 128 public static Builder builder() { 129 return new Builder(); 130 } 131 132 public static Builder builder(BackOff template) { 133 return new Builder().read(template); 134 } 135 136 /** 137 * A builder for {@link BackOff} 138 */ 139 public static final class Builder { 140 private Duration delay = BackOff.DEFAULT_DELAY; 141 private Duration maxDelay = BackOff.MAX_DURATION; 142 private Duration maxElapsedTime = BackOff.MAX_DURATION; 143 private Long maxAttempts = Long.MAX_VALUE; 144 private Double multiplier = BackOff.DEFAULT_MULTIPLIER; 145 146 /** 147 * Read values from the given {@link BackOff} 148 */ 149 public Builder read(BackOff template) { 150 delay = template.delay; 151 maxDelay = template.maxDelay; 152 maxElapsedTime = template.maxElapsedTime; 153 maxAttempts = template.maxAttempts; 154 multiplier = template.multiplier; 155 156 return this; 157 } 158 159 public Builder delay(Duration delay) { 160 this.delay = delay; 161 return this; 162 } 163 164 public Builder delay(long delay, TimeUnit unit) { 165 return delay(Duration.ofMillis(unit.toMillis(delay))); 166 } 167 168 public Builder delay(long delay) { 169 return delay(Duration.ofMillis(delay)); 170 } 171 172 public Builder maxDelay(Duration maxDelay) { 173 this.maxDelay = maxDelay; 174 return this; 175 } 176 177 public Builder maxDelay(long maxDelay, TimeUnit unit) { 178 return maxDelay(Duration.ofMillis(unit.toMillis(maxDelay))); 179 } 180 181 public Builder maxDelay(long maxDelay) { 182 return maxDelay(Duration.ofMillis(maxDelay)); 183 } 184 185 public Builder maxElapsedTime(Duration maxElapsedTime) { 186 this.maxElapsedTime = maxElapsedTime; 187 return this; 188 } 189 190 public Builder maxElapsedTime(long maxElapsedTime, TimeUnit unit) { 191 return maxElapsedTime(Duration.ofMillis(unit.toMillis(maxElapsedTime))); 192 } 193 194 public Builder maxElapsedTime(long maxElapsedTime) { 195 return maxElapsedTime(Duration.ofMillis(maxElapsedTime)); 196 } 197 198 public Builder maxAttempts(Long attempts) { 199 this.maxAttempts = attempts; 200 return this; 201 } 202 203 public Builder multiplier(Double multiplier) { 204 this.multiplier = multiplier; 205 return this; 206 } 207 208 /** 209 * Build a new instance of {@link BackOff} 210 */ 211 public BackOff build() { 212 return new BackOff(delay, maxDelay, maxElapsedTime, maxAttempts, multiplier); 213 } 214 } 215}