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