From 677473cdfc42b9fd83623902e80de946f108825c Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Thu, 15 Mar 2018 08:02:16 +0200 Subject: Update docs --- NEWS | 27 ++++++++++++++++++++++++--- configure.ac | 4 ++-- doc/eclat.conf.5 | 33 ++++++++++++++++++++++++++++++++- src/config.c | 2 +- src/util.c | 12 ++++++------ 5 files changed, 65 insertions(+), 13 deletions(-) diff --git a/NEWS b/NEWS index d71f794..c7edebd 100644 --- a/NEWS +++ b/NEWS @@ -1,10 +1,31 @@ -Eclat NEWS -- history of user-visible changes. 2015-11-19 -Copyright (C) 2012-2015 Sergey Poznyakoff +Eclat NEWS -- history of user-visible changes. 2018-03-15 +Copyright (C) 2012-2018 Sergey Poznyakoff See the end of file for copying conditions. Please send Eclat bug reports to -Version 1.1.90 (Git) +Version 1.1.91 (Git) + +* Exponential backoff with jitter + +If AWS responds with a RequestLimitExceeded code, eclat retries the +request using exponential backoff with jitter algorithm. The algorithm +is controlled by two values: max-retry-interval and total-retry-timeout. +When the RequestLimitExceeded error is returned, eclat will sleep for +2 seconds and then retry the request. For each subsequent +RequestLimitExceeded error, it will calculate the timeout using the +following formula: + + t = rand(0, min(M, 2 ** N)) + 1 + +where N is the attempt number, M is the value of max-retry-interval +parameter, 'rand(a,b)' selects the integer random number X such that +0 <= X <= b, and '**' denotes power operator. The attempts to resend +the request will continue until either a response other than +RequestLimitExceeded is received (be it a response to the query or +another error response), or the total time spent in the retry loop +becomes equal to or greater than total-retry-timeout, whichever occurs +first. * VPC Support diff --git a/configure.ac b/configure.ac index a2e0cfb..1673dbb 100644 --- a/configure.ac +++ b/configure.ac @@ -1,5 +1,5 @@ # This file is part of Eclat -*- autoconf -*- -# Copyright (C) 2012-2015 Sergey Poznyakoff +# Copyright (C) 2012-2018 Sergey Poznyakoff # # Eclat is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by @@ -15,7 +15,7 @@ # along with Eclat. If not, see . AC_PREREQ(2.63) -AC_INIT([eclat], 1.1.90, [bug-eclat@gnu.org.ua],, +AC_INIT([eclat], 1.1.91, [bug-eclat@gnu.org.ua],, [http://www.gnu.org.ua/software/eclat]) AC_CONFIG_SRCDIR([src/eclat.h]) AC_CONFIG_AUX_DIR([build-aux]) diff --git a/doc/eclat.conf.5 b/doc/eclat.conf.5 index c896dba..bc6a567 100644 --- a/doc/eclat.conf.5 +++ b/doc/eclat.conf.5 @@ -13,7 +13,7 @@ .\" .\" You should have received a copy of the GNU General Public License .\" along with Eclat. If not, see . -.TH ECLAT.CONF 5 "November 19, 2015" "ECLAT" "Eclat User Reference" +.TH ECLAT.CONF 5 "March 15, 2018" "ECLAT" "Eclat User Reference" .SH NAME eclat.conf \- configuration file for .BR eclat (1). @@ -469,6 +469,37 @@ This is a shortcut for \fBauthentication\-provider file \fIname\fR. \fBsignature\-version\fR \fIN\fR; Declares the signature version. Valid values for \fIN\fR are \fB2\fR, which is the default, and \fB4\fR, which provides a better security. +.SH RETRY ON ERRORS +If AWS responds with a \fBRequestLimitExceeded\fR code, \fBeclat\fR +retries the request using exponential backoff with jitter algorithm. +The algorithm is controlled by two configuration values: +.B max\-retry\-interval +and +.BR total\-retry\-timeout . +When the \fBRequestLimitExceeded\fR error is returned, \fBeclat\fR +will sleep for up to 2 seconds and then retry the request. For each +subsequent \fBRequestLimitExceeded\fR error, it will calculate the +timeout using the following formula: +.EX + t = rand(0, min(M, 2 ** N)) + 1 +.EE +where N is the attempt number, M is the value of max-retry-interval +parameter, 'rand(a,b)' selects the integer random number X such that +0 <= X <= b, and '**' is the power operator. The attempts to resend +the request will continue until either a response other than +\fBRequestLimitExceeded\fR is received (be it a response to the query or +another error response), or the total time spent in the retry loop +becomes equal to or greater than +.BR total-retry-timeout , +whichever occurs +first. +.PP +Default values are: +.PP +.EX +max-retry-interval 600; +total-retry-timeout 1800; +.EE .SH INSTANCE STORE CONFIGURATION The \fBinstance\-store\fR compound statement configures HTTP access to the instance store. By default, \fBeclat\fR uses standard AWS values. diff --git a/src/config.c b/src/config.c index 6fac842..069ddd0 100644 --- a/src/config.c +++ b/src/config.c @@ -399,7 +399,7 @@ static struct grecs_keyword eclat_kw[] = { { "max-retry-interval", "seconds", "Maximum interval between retries in exponential backoff algorithm.", grecs_type_ulong, GRECS_DFLT, &max_retry_sleep }, - { "retry-timeout", "seconds", + { "total-retry-timeout", "seconds", "Give up retrying after this many seconds", grecs_type_ulong, GRECS_DFLT, &max_retry_time }, { "default-region", "name", diff --git a/src/util.c b/src/util.c index 3ada220..43b27ef 100644 --- a/src/util.c +++ b/src/util.c @@ -236,7 +236,7 @@ eclat_send_request(struct ec2_request *orig, struct grecs_node **ret_tree) endtime = time(NULL) + max_retry_time; tts = 2; - do { + while (1) { struct grecs_node *node; struct ec2_request *req; @@ -301,11 +301,14 @@ eclat_send_request(struct ec2_request *orig, struct grecs_node **ret_tree) if (dry_run_mode) debug(ECLAT_DEBCAT_MAIN, 1, ("not sending request")); else { + grecs_tree_free(xmltree); + res = curl_easy_perform(io->curl); if (res == CURLE_OK) { xmltree = eclat_io_finish(io); } else { err("CURL: %s", curl_easy_strerror(res)); + xmltree = NULL; ret = 1; } } @@ -314,7 +317,7 @@ eclat_send_request(struct ec2_request *orig, struct grecs_node **ret_tree) curl_slist_free_all(headers); eclat_request_free(req); - if (ret) + if (ret || time(NULL) >= endtime) break; node = grecs_find_node(xmltree, ".Response.Errors.Error.Code"); @@ -329,9 +332,6 @@ eclat_send_request(struct ec2_request *orig, struct grecs_node **ret_tree) if (strcmp(node->v.value->v.string, "RequestLimitExceeded")) break; - grecs_tree_free(xmltree); - xmltree = NULL; - t = random() % tts + 1; warn("request limit exceeded; sleeping for %lu seconds", t); sleep(t); @@ -340,7 +340,7 @@ eclat_send_request(struct ec2_request *orig, struct grecs_node **ret_tree) if (tts == 0 || tts > max_retry_sleep) tts = max_retry_sleep; } - } while (time(NULL) < endtime); + } *ret_tree = xmltree; return ret; -- cgit v1.2.1