001 /** 002 * 003 * Licensed to the Apache Software Foundation (ASF) under one or more 004 * contributor license agreements. See the NOTICE file distributed with 005 * this work for additional information regarding copyright ownership. 006 * The ASF licenses this file to You under the Apache License, Version 2.0 007 * (the "License"); you may not use this file except in compliance with 008 * the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 package org.apache.camel.processor; 019 020 import java.io.Serializable; 021 import java.util.Random; 022 023 // Code taken from the ActiveMQ codebase 024 025 /** 026 * The policy used to decide how many times to redeliver and the time between the redeliveries before being sent to a 027 * <a href="http://activemq.apache.org/camel/dead-letter-channel.html">Dead Letter Channel</a> 028 * 029 * @version $Revision: 530858 $ 030 */ 031 public class RedeliveryPolicy implements Cloneable, Serializable { 032 protected static transient Random randomNumberGenerator; 033 protected int maximumRedeliveries = 6; 034 protected long initialRedeliveryDelay = 1000L; 035 protected double backOffMultiplier = 2; 036 protected boolean useExponentialBackOff = false; 037 // +/-15% for a 30% spread -cgs 038 protected double collisionAvoidanceFactor = 0.15d; 039 protected boolean useCollisionAvoidance = false; 040 041 public RedeliveryPolicy() { 042 } 043 044 @Override 045 public String toString() { 046 return "RedeliveryPolicy[maximumRedeliveries=" + maximumRedeliveries + "]"; 047 } 048 049 public RedeliveryPolicy copy() { 050 try { 051 return (RedeliveryPolicy) clone(); 052 } 053 catch (CloneNotSupportedException e) { 054 throw new RuntimeException("Could not clone: " + e, e); 055 } 056 } 057 058 /** 059 * Returns true if the policy decides that the message exchange should be redelivered 060 */ 061 public boolean shouldRedeliver(int redeliveryCounter) { 062 return redeliveryCounter < getMaximumRedeliveries(); 063 } 064 065 // Builder methods 066 //------------------------------------------------------------------------- 067 068 /** 069 * Sets the maximum number of times a message exchange will be redelivered 070 */ 071 public RedeliveryPolicy maximumRedeliveries(int maximumRedeliveries) { 072 setMaximumRedeliveries(maximumRedeliveries); 073 return this; 074 } 075 076 /** 077 * Sets the initial redelivery delay in milliseconds on the first redelivery 078 */ 079 public RedeliveryPolicy initialRedeliveryDelay(long initialRedeliveryDelay) { 080 setInitialRedeliveryDelay(initialRedeliveryDelay); 081 return this; 082 } 083 084 /** 085 * Enables collision avoidence which adds some randomization to the backoff timings to reduce contention probability 086 */ 087 public RedeliveryPolicy useCollisionAvoidance() { 088 setUseCollisionAvoidance(true); 089 return this; 090 } 091 092 /** 093 * Enables exponential backof using the {@link #getBackOffMultiplier()} to increase the time between retries 094 */ 095 public RedeliveryPolicy useExponentialBackOff() { 096 setUseExponentialBackOff(true); 097 return this; 098 } 099 100 /** 101 * Enables exponential backoff and sets the multiplier used to increase the delay between redeliveries 102 */ 103 public RedeliveryPolicy backOffMultiplier(double backOffMultiplier) { 104 useExponentialBackOff(); 105 setBackOffMultiplier(backOffMultiplier); 106 return this; 107 } 108 109 /** 110 * Enables collision avoidence and sets the percentage used 111 */ 112 public RedeliveryPolicy collisionAvoidancePercent(short collisionAvoidancePercent) { 113 useCollisionAvoidance(); 114 setCollisionAvoidancePercent(collisionAvoidancePercent); 115 return this; 116 } 117 118 // Properties 119 //------------------------------------------------------------------------- 120 public double getBackOffMultiplier() { 121 return backOffMultiplier; 122 } 123 124 /** 125 * Sets the multiplier used to increase the delay between redeliveries if {@link #setUseExponentialBackOff(boolean)} is enabled 126 */ 127 public void setBackOffMultiplier(double backOffMultiplier) { 128 this.backOffMultiplier = backOffMultiplier; 129 } 130 131 public short getCollisionAvoidancePercent() { 132 return (short) Math.round(collisionAvoidanceFactor * 100); 133 } 134 135 /** 136 * Sets the percentage used for collision avoidence if enabled via {@link #setUseCollisionAvoidance(boolean)} 137 */ 138 public void setCollisionAvoidancePercent(short collisionAvoidancePercent) { 139 this.collisionAvoidanceFactor = collisionAvoidancePercent * 0.01d; 140 } 141 142 public double getCollisionAvoidanceFactor() { 143 return collisionAvoidanceFactor; 144 } 145 146 /** 147 * Sets the factor used for collision avoidence if enabled via {@link #setUseCollisionAvoidance(boolean)} 148 */ 149 public void setCollisionAvoidanceFactor(double collisionAvoidanceFactor) { 150 this.collisionAvoidanceFactor = collisionAvoidanceFactor; 151 } 152 153 public long getInitialRedeliveryDelay() { 154 return initialRedeliveryDelay; 155 } 156 157 /** 158 * Sets the initial redelivery delay in milliseconds on the first redelivery 159 */ 160 public void setInitialRedeliveryDelay(long initialRedeliveryDelay) { 161 this.initialRedeliveryDelay = initialRedeliveryDelay; 162 } 163 164 public int getMaximumRedeliveries() { 165 return maximumRedeliveries; 166 } 167 168 /** 169 * Sets the maximum number of times a message exchange will be redelivered 170 */ 171 public void setMaximumRedeliveries(int maximumRedeliveries) { 172 this.maximumRedeliveries = maximumRedeliveries; 173 } 174 175 public long getRedeliveryDelay(long previousDelay) { 176 long redeliveryDelay; 177 178 if (previousDelay == 0) { 179 redeliveryDelay = initialRedeliveryDelay; 180 } 181 else if (useExponentialBackOff && backOffMultiplier > 1) { 182 redeliveryDelay = Math.round(backOffMultiplier * previousDelay); 183 } 184 else { 185 redeliveryDelay = previousDelay; 186 } 187 188 if (useCollisionAvoidance) { 189 190 /* 191 * First random determines +/-, second random determines how far to 192 * go in that direction. -cgs 193 */ 194 Random random = getRandomNumberGenerator(); 195 double variance = (random.nextBoolean() ? collisionAvoidanceFactor : -collisionAvoidanceFactor) * random.nextDouble(); 196 redeliveryDelay += redeliveryDelay * variance; 197 } 198 199 return redeliveryDelay; 200 } 201 202 public boolean isUseCollisionAvoidance() { 203 return useCollisionAvoidance; 204 } 205 206 /** 207 * Enables/disables collision avoidence which adds some randomization to the backoff timings to reduce contention probability 208 */ 209 public void setUseCollisionAvoidance(boolean useCollisionAvoidance) { 210 this.useCollisionAvoidance = useCollisionAvoidance; 211 } 212 213 public boolean isUseExponentialBackOff() { 214 return useExponentialBackOff; 215 } 216 217 /** 218 * Enables/disables exponential backof using the {@link #getBackOffMultiplier()} to increase the time between retries 219 */ 220 public void setUseExponentialBackOff(boolean useExponentialBackOff) { 221 this.useExponentialBackOff = useExponentialBackOff; 222 } 223 224 protected static synchronized Random getRandomNumberGenerator() { 225 if (randomNumberGenerator == null) { 226 randomNumberGenerator = new Random(); 227 } 228 return randomNumberGenerator; 229 } 230 }