| 
									
										
										
										
											2015-10-13 12:27:50 +02:00
										 |  |  | package retry | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"time" | 
					
						
							| 
									
										
										
										
											2016-12-04 09:10:47 +01:00
										 |  |  | 	"v2ray.com/core/common/errors" | 
					
						
							| 
									
										
										
										
											2015-10-13 12:27:50 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var ( | 
					
						
							| 
									
										
										
										
											2016-06-27 08:53:35 +02:00
										 |  |  | 	ErrRetryFailed = errors.New("All retry attempts failed.") | 
					
						
							| 
									
										
										
										
											2015-10-13 12:27:50 +02:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-02 09:58:00 +01:00
										 |  |  | // Strategy is a way to retry on a specific function. | 
					
						
							| 
									
										
										
										
											2015-12-02 09:46:19 +01:00
										 |  |  | type Strategy interface { | 
					
						
							| 
									
										
										
										
											2015-12-02 12:47:54 +01:00
										 |  |  | 	// On performs a retry on a specific function, until it doesn't return any error. | 
					
						
							| 
									
										
										
										
											2015-10-13 12:27:50 +02:00
										 |  |  | 	On(func() error) error | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | type retryer struct { | 
					
						
							| 
									
										
										
										
											2016-11-20 21:47:51 +01:00
										 |  |  | 	totalAttempt int | 
					
						
							|  |  |  | 	nextDelay    func() uint32 | 
					
						
							| 
									
										
										
										
											2015-10-13 12:27:50 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-02 09:58:00 +01:00
										 |  |  | // On implements Strategy.On. | 
					
						
							| 
									
										
										
										
											2015-10-13 12:27:50 +02:00
										 |  |  | func (r *retryer) On(method func() error) error { | 
					
						
							|  |  |  | 	attempt := 0 | 
					
						
							| 
									
										
										
										
											2016-11-20 21:47:51 +01:00
										 |  |  | 	for attempt < r.totalAttempt { | 
					
						
							| 
									
										
										
										
											2015-10-13 12:27:50 +02:00
										 |  |  | 		err := method() | 
					
						
							|  |  |  | 		if err == nil { | 
					
						
							|  |  |  | 			return nil | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-11-20 21:47:51 +01:00
										 |  |  | 		delay := r.nextDelay() | 
					
						
							| 
									
										
										
										
											2015-10-13 12:27:50 +02:00
										 |  |  | 		<-time.After(time.Duration(delay) * time.Millisecond) | 
					
						
							| 
									
										
										
										
											2015-10-14 00:57:00 +02:00
										 |  |  | 		attempt++ | 
					
						
							| 
									
										
										
										
											2015-10-13 12:27:50 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-11-20 21:47:51 +01:00
										 |  |  | 	return ErrRetryFailed | 
					
						
							| 
									
										
										
										
											2015-10-13 12:27:50 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-12-02 09:58:00 +01:00
										 |  |  | // Timed returns a retry strategy with fixed interval. | 
					
						
							| 
									
										
										
										
											2016-11-20 21:47:51 +01:00
										 |  |  | func Timed(attempts int, delay uint32) Strategy { | 
					
						
							| 
									
										
										
										
											2015-10-13 12:27:50 +02:00
										 |  |  | 	return &retryer{ | 
					
						
							| 
									
										
										
										
											2016-11-20 21:47:51 +01:00
										 |  |  | 		totalAttempt: attempts, | 
					
						
							|  |  |  | 		nextDelay: func() uint32 { | 
					
						
							| 
									
										
										
										
											2015-10-13 12:27:50 +02:00
										 |  |  | 			return delay | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2016-11-20 21:47:51 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | func ExponentialBackoff(attempts int, delay uint32) Strategy { | 
					
						
							|  |  |  | 	nextDelay := uint32(0) | 
					
						
							|  |  |  | 	return &retryer{ | 
					
						
							|  |  |  | 		totalAttempt: attempts, | 
					
						
							|  |  |  | 		nextDelay: func() uint32 { | 
					
						
							|  |  |  | 			r := nextDelay | 
					
						
							|  |  |  | 			nextDelay += delay | 
					
						
							|  |  |  | 			return r | 
					
						
							|  |  |  | 		}, | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } |