MEDIUM: acme: use Retry-After value for retries

Parse the Retry-After header in response and store it in order to use
the value as the next delay for the next retry, fallback to 3s if the
value couldn't be parse or does not exist.
This commit is contained in:
William Lallemand 2025-04-24 17:31:51 +02:00
parent 69b051d1dc
commit bb768b3e26
2 changed files with 40 additions and 3 deletions

View File

@ -61,6 +61,7 @@ struct acme_ctx {
enum acme_st state;
enum http_st http_state;
int retries;
int retryafter;
struct httpclient *hc;
struct acme_cfg *cfg;
struct ckch_store *store;

View File

@ -720,6 +720,10 @@ int acme_res_certificate(struct task *task, struct acme_ctx *ctx, char **errmsg)
istfree(&ctx->nonce);
ctx->nonce = istdup(hdr->v);
}
/* get the next retry timing */
if (isteqi(hdr->n, ist("Retry-After"))) {
ctx->retryafter = atol(hdr->v.ptr);
}
}
if (hc->res.status < 200 || hc->res.status >= 300) {
@ -787,6 +791,10 @@ int acme_res_chkorder(struct task *task, struct acme_ctx *ctx, char **errmsg)
istfree(&ctx->nonce);
ctx->nonce = istdup(hdr->v);
}
/* get the next retry timing */
if (isteqi(hdr->n, ist("Retry-After"))) {
ctx->retryafter = atol(hdr->v.ptr);
}
}
if (hc->res.status < 200 || hc->res.status >= 300) {
@ -912,6 +920,10 @@ int acme_res_finalize(struct task *task, struct acme_ctx *ctx, char **errmsg)
istfree(&ctx->nonce);
ctx->nonce = istdup(hdr->v);
}
/* get the next retry timing */
if (isteqi(hdr->n, ist("Retry-After"))) {
ctx->retryafter = atol(hdr->v.ptr);
}
}
if (hc->res.status < 200 || hc->res.status >= 300) {
@ -999,6 +1011,10 @@ int acme_res_challenge(struct task *task, struct acme_ctx *ctx, struct acme_auth
istfree(&ctx->nonce);
ctx->nonce = istdup(hdr->v);
}
/* get the next retry timing */
if (isteqi(hdr->n, ist("Retry-After"))) {
ctx->retryafter = atol(hdr->v.ptr);
}
}
if (hc->res.status < 200 || hc->res.status >= 300 || mjson_find(hc->res.buf.area, hc->res.buf.data, "$.error", NULL, NULL) == MJSON_TOK_OBJECT) {
@ -1087,6 +1103,11 @@ int acme_res_auth(struct task *task, struct acme_ctx *ctx, struct acme_auth *aut
istfree(&ctx->nonce);
ctx->nonce = istdup(hdr->v);
}
/* get the next retry timing */
if (isteqi(hdr->n, ist("Retry-After"))) {
ctx->retryafter = atol(hdr->v.ptr);
}
}
if (hc->res.status < 200 || hc->res.status >= 300) {
@ -1238,6 +1259,10 @@ int acme_res_neworder(struct task *task, struct acme_ctx *ctx, char **errmsg)
istfree(&ctx->nonce);
ctx->nonce = istdup(hdr->v);
}
/* get the next retry timing */
if (isteqi(hdr->n, ist("Retry-After"))) {
ctx->retryafter = atol(hdr->v.ptr);
}
/* get the order URL */
if (isteqi(hdr->n, ist("Location"))) {
istfree(&ctx->order);
@ -1386,6 +1411,10 @@ int acme_res_account(struct task *task, struct acme_ctx *ctx, int newaccount, ch
istfree(&ctx->kid);
ctx->kid = istdup(hdr->v);
}
/* get the next retry timing */
if (isteqi(hdr->n, ist("Retry-After"))) {
ctx->retryafter = atol(hdr->v.ptr);
}
if (isteqi(hdr->n, ist("Replay-Nonce"))) {
istfree(&ctx->nonce);
ctx->nonce = istdup(hdr->v);
@ -1742,9 +1771,16 @@ retry:
int delay = 1;
int i;
for (i = 0; i < ACME_RETRY - ctx->retries; i++)
delay *= 3;
send_log(NULL, LOG_NOTICE, "acme: %s: %s, retrying in %ds (%d/%d)...\n", ctx->store->path, errmsg ? errmsg : "", delay, ACME_RETRY - ctx->retries, ACME_RETRY);
if (ctx->retryafter > 0) {
/* Use the Retry-After value from the header */
delay = ctx->retryafter;
ctx->retryafter = 0;
} else {
/* else does an exponential backoff * 3 */
for (i = 0; i < ACME_RETRY - ctx->retries; i++)
delay *= 3;
}
send_log(NULL, LOG_NOTICE, "acme: %s: %s, retrying in %ds (%d/%d retries)...\n", ctx->store->path, errmsg ? errmsg : "", delay, ACME_RETRY - ctx->retries, ACME_RETRY);
task->expire = tick_add(now_ms, delay * 1000);
} else {