Skip to content

Commit 44a6c14

Browse files
authored
Merge pull request #26 from minfrin/jitter
Add optional jitter to the delay.
2 parents 727d897 + 989056f commit 44a6c14

File tree

2 files changed

+65
-5
lines changed

2 files changed

+65
-5
lines changed

ChangeLog

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11

22
Changes with v1.0.6
33

4+
*) Add optional jitter to the delay. [Graham Leggett]
5+
46
*) Avoid the final delay when running a command a
57
specific number of times. [Graham Leggett]
68

retry.c

Lines changed: 63 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#include <poll.h>
2929
#include <sys/uio.h>
3030
#include <ctype.h>
31+
#include <time.h>
3132

3233
#include "config.h"
3334

@@ -50,6 +51,7 @@
5051
static struct option long_options[] =
5152
{
5253
{"delay", required_argument, NULL, 'd'},
54+
{"jitter", required_argument, NULL, 'j'},
5355
{"message", required_argument, NULL, 'm'},
5456
{"until", required_argument, NULL, 'u'},
5557
{"while", required_argument, NULL, 'w'},
@@ -116,6 +118,10 @@ static int help(const char *name, const char *msg, int code)
116118
" delays allow subsequent delays to be different,\n"
117119
" with the last delay repeated.\n"
118120
"\n"
121+
" -j seconds, --jitter=seconds The number of seconds of jitter\n"
122+
" to add to each delay attempt. A random number of nanoseconds between\n"
123+
" zero and this number will be added to the delay.\n"
124+
"\n"
119125
" -m message, --message=message A message to include in the notification\n"
120126
" when repeat has backed off. Defaults to the\n"
121127
" command name.\n"
@@ -185,7 +191,7 @@ static int help(const char *name, const char *msg, int code)
185191
"\n"
186192
" In this example, we try three times before giving up.\n"
187193
"\n"
188-
"\t~$ retry --times=3 -- false\n"
194+
"\t~$ retry --times=3 -- false\n"
189195
"\tretry: false returned 1, backing off for 10 seconds and trying again...\n"
190196
"\tretry: false returned 1, backing off for 10 seconds and trying again...\n"
191197
"\tretry: false returned 1, giving up.\n"
@@ -405,19 +411,52 @@ static int pump(const char *name, pump_t *pumps)
405411
return 0;
406412
}
407413

414+
void seed_jitter()
415+
{
416+
struct timespec ts;
417+
418+
/*
419+
* Seed the random number generator with the number of
420+
* nanoseconds returned by the system clock.
421+
*
422+
* Two retries should be unlikely to return the same
423+
* number of nanoseconds.
424+
*/
425+
426+
clock_gettime(CLOCK_REALTIME, &ts);
427+
428+
srand((unsigned int)ts.tv_nsec);
429+
430+
return;
431+
}
432+
433+
void add_jitter(long int j, struct timespec *ts)
434+
{
435+
/*
436+
* We assume that sampling bias is not a big enough
437+
* problem for jitter.
438+
*
439+
* The nanoseconds should smear a thundering herd.
440+
*/
441+
ts->tv_sec += rand() % (j);
442+
ts->tv_nsec += rand() % (1000000000);
443+
}
444+
408445
int main (int argc, char **argv)
409446
{
410447
const char *name = argv[0];
411448
const char *repeat_until = "success";
412449
const char *repeat_while = NULL;
413450
const char *message = NULL;
414451
char *delay = DEFAULT_DELAY;
452+
struct timespec ts;
415453
pump_t pumps[PUMPS] = { 0 };
416454
int c, status = 0, i;
417455
long int d = 0;
456+
long int j = 0;
418457
long int times = DEFAULT_TIMES;
419458

420-
while ((c = getopt_long(argc, argv, "+d:m:t:u:w:hv", long_options, NULL)) != -1) {
459+
while ((c = getopt_long(argc, argv, "+d:j:m:t:u:w:hv", long_options, NULL)) != -1) {
421460

422461
switch (c)
423462
{
@@ -435,6 +474,16 @@ int main (int argc, char **argv)
435474

436475
} while (optarg++[0] == ',');
437476

477+
break;
478+
case 'j':
479+
errno = 0;
480+
481+
j = strtol(optarg, &optarg, 10);
482+
483+
if (errno || optarg[0] || j < 0) {
484+
return help(name, "Jitter must be bigger or equal to 0.\n", EXIT_FAILURE);
485+
}
486+
438487
break;
439488
case 'm':
440489
message = optarg;
@@ -482,6 +531,8 @@ int main (int argc, char **argv)
482531
return help(name, "No command specified.\n", EXIT_FAILURE);
483532
}
484533

534+
seed_jitter();
535+
485536
while (times) {
486537
pid_t w, f;
487538
int inpair[2], outpair[2];
@@ -617,13 +668,20 @@ int main (int argc, char **argv)
617668
delay++;
618669
}
619670

620-
if (d) {
671+
ts.tv_sec = d;
672+
ts.tv_nsec = 0;
673+
674+
if (j) {
675+
add_jitter(j, &ts);
676+
}
677+
678+
if (ts.tv_sec && ts.tv_nsec) {
621679
fprintf(stderr,
622680
"%s: %s returned %d, backing off for %ld second%s and trying again...\n",
623681
name, message ? message : argv[optind], status,
624-
d, d > 1 ? "s" : "");
682+
(long)ts.tv_sec, ts.tv_sec != 1 ? "s" : "");
625683

626-
sleep(d);
684+
nanosleep(&ts, NULL);
627685
}
628686
else {
629687
fprintf(stderr,

0 commit comments

Comments
 (0)