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 */ 017 package org.apache.camel.processor; 018 019 import java.io.Serializable; 020 import java.util.Random; 021 022 // Code taken from the ActiveMQ codebase 023 024 /** 025 * The policy used to decide how many times to redeliver and the time between 026 * the redeliveries before being sent to a <a 027 * href="http://activemq.apache.org/camel/dead-letter-channel.html">Dead Letter 028 * Channel</a> 029 * <p> 030 * The default values is: 031 * <ul> 032 * <li>maximumRedeliveries = 6</li> 033 * <li>initialRedeliveryDelay = 1000L</li> 034 * <li>backOffMultiplier = 2</li> 035 * <li>useExponentialBackOff = false</li> 036 * <li>collisionAvoidanceFactor = 0.15d</li> 037 * <li>useCollisionAvoidance = false</li> 038 * </ul> 039 * 040 * @version $Revision: 37863 $ 041 */ 042 public class RedeliveryPolicy implements Cloneable, Serializable { 043 protected static transient Random randomNumberGenerator; 044 protected int maximumRedeliveries = 6; 045 protected long initialRedeliveryDelay = 1000L; 046 protected double backOffMultiplier = 2; 047 protected boolean useExponentialBackOff; 048 // +/-15% for a 30% spread -cgs 049 protected double collisionAvoidanceFactor = 0.15d; 050 protected boolean useCollisionAvoidance; 051 052 public RedeliveryPolicy() { 053 } 054 055 @Override 056 public String toString() { 057 return "RedeliveryPolicy[maximumRedeliveries=" + maximumRedeliveries + "]"; 058 } 059 060 public RedeliveryPolicy copy() { 061 try { 062 return (RedeliveryPolicy)clone(); 063 } catch (CloneNotSupportedException e) { 064 throw new RuntimeException("Could not clone: " + e, e); 065 } 066 } 067 068 /** 069 * Returns true if the policy decides that the message exchange should be 070 * redelivered 071 */ 072 public boolean shouldRedeliver(int redeliveryCounter) { 073 if (getMaximumRedeliveries() < 0) { 074 return true; 075 } 076 return redeliveryCounter < getMaximumRedeliveries(); 077 } 078 079 // Builder methods 080 // ------------------------------------------------------------------------- 081 082 /** 083 * Sets the maximum number of times a message exchange will be redelivered 084 */ 085 public RedeliveryPolicy maximumRedeliveries(int maximumRedeliveries) { 086 setMaximumRedeliveries(maximumRedeliveries); 087 return this; 088 } 089 090 /** 091 * Sets the initial redelivery delay in milliseconds on the first redelivery 092 */ 093 public RedeliveryPolicy initialRedeliveryDelay(long initialRedeliveryDelay) { 094 setInitialRedeliveryDelay(initialRedeliveryDelay); 095 return this; 096 } 097 098 /** 099 * Enables collision avoidence which adds some randomization to the backoff 100 * timings to reduce contention probability 101 */ 102 public RedeliveryPolicy useCollisionAvoidance() { 103 setUseCollisionAvoidance(true); 104 return this; 105 } 106 107 /** 108 * Enables exponential backof using the {@link #getBackOffMultiplier()} to 109 * increase the time between retries 110 */ 111 public RedeliveryPolicy useExponentialBackOff() { 112 setUseExponentialBackOff(true); 113 return this; 114 } 115 116 /** 117 * Enables exponential backoff and sets the multiplier used to increase the 118 * delay between redeliveries 119 */ 120 public RedeliveryPolicy backOffMultiplier(double multiplier) { 121 useExponentialBackOff(); 122 setBackOffMultiplier(multiplier); 123 return this; 124 } 125 126 /** 127 * Enables collision avoidence and sets the percentage used 128 */ 129 public RedeliveryPolicy collisionAvoidancePercent(double collisionAvoidancePercent) { 130 useCollisionAvoidance(); 131 setCollisionAvoidancePercent(collisionAvoidancePercent); 132 return this; 133 } 134 135 // Properties 136 // ------------------------------------------------------------------------- 137 public double getBackOffMultiplier() { 138 return backOffMultiplier; 139 } 140 141 /** 142 * Sets the multiplier used to increase the delay between redeliveries if 143 * {@link #setUseExponentialBackOff(boolean)} is enabled 144 */ 145 public void setBackOffMultiplier(double backOffMultiplier) { 146 this.backOffMultiplier = backOffMultiplier; 147 } 148 149 public short getCollisionAvoidancePercent() { 150 return (short)Math.round(collisionAvoidanceFactor * 100); 151 } 152 153 /** 154 * Sets the percentage used for collision avoidence if enabled via 155 * {@link #setUseCollisionAvoidance(boolean)} 156 */ 157 public void setCollisionAvoidancePercent(double collisionAvoidancePercent) { 158 this.collisionAvoidanceFactor = collisionAvoidancePercent * 0.01d; 159 } 160 161 public double getCollisionAvoidanceFactor() { 162 return collisionAvoidanceFactor; 163 } 164 165 /** 166 * Sets the factor used for collision avoidence if enabled via 167 * {@link #setUseCollisionAvoidance(boolean)} 168 */ 169 public void setCollisionAvoidanceFactor(double collisionAvoidanceFactor) { 170 this.collisionAvoidanceFactor = collisionAvoidanceFactor; 171 } 172 173 public long getInitialRedeliveryDelay() { 174 return initialRedeliveryDelay; 175 } 176 177 /** 178 * Sets the initial redelivery delay in milliseconds on the first redelivery 179 */ 180 public void setInitialRedeliveryDelay(long initialRedeliveryDelay) { 181 this.initialRedeliveryDelay = initialRedeliveryDelay; 182 } 183 184 public int getMaximumRedeliveries() { 185 return maximumRedeliveries; 186 } 187 188 /** 189 * Sets the maximum number of times a message exchange will be redelivered. 190 * Setting a negative value will retry forever. 191 */ 192 public void setMaximumRedeliveries(int maximumRedeliveries) { 193 this.maximumRedeliveries = maximumRedeliveries; 194 } 195 196 public long getRedeliveryDelay(long previousDelay) { 197 long redeliveryDelay; 198 199 if (previousDelay == 0) { 200 redeliveryDelay = initialRedeliveryDelay; 201 } else if (useExponentialBackOff && backOffMultiplier > 1) { 202 redeliveryDelay = Math.round(backOffMultiplier * previousDelay); 203 } else { 204 redeliveryDelay = previousDelay; 205 } 206 207 if (useCollisionAvoidance) { 208 209 /* 210 * First random determines +/-, second random determines how far to 211 * go in that direction. -cgs 212 */ 213 Random random = getRandomNumberGenerator(); 214 double variance = (random.nextBoolean() ? collisionAvoidanceFactor : -collisionAvoidanceFactor) 215 * random.nextDouble(); 216 redeliveryDelay += redeliveryDelay * variance; 217 } 218 219 return redeliveryDelay; 220 } 221 222 public boolean isUseCollisionAvoidance() { 223 return useCollisionAvoidance; 224 } 225 226 /** 227 * Enables/disables collision avoidence which adds some randomization to the 228 * backoff timings to reduce contention probability 229 */ 230 public void setUseCollisionAvoidance(boolean useCollisionAvoidance) { 231 this.useCollisionAvoidance = useCollisionAvoidance; 232 } 233 234 public boolean isUseExponentialBackOff() { 235 return useExponentialBackOff; 236 } 237 238 /** 239 * Enables/disables exponential backof using the 240 * {@link #getBackOffMultiplier()} to increase the time between retries 241 */ 242 public void setUseExponentialBackOff(boolean useExponentialBackOff) { 243 this.useExponentialBackOff = useExponentialBackOff; 244 } 245 246 protected static synchronized Random getRandomNumberGenerator() { 247 if (randomNumberGenerator == null) { 248 randomNumberGenerator = new Random(); 249 } 250 return randomNumberGenerator; 251 } 252 }