Skip to content

Commit 6773d55

Browse files
committed
Retry S3 download on 403 error
1 parent 8bad06d commit 6773d55

File tree

6 files changed

+99
-18
lines changed

6 files changed

+99
-18
lines changed

modules/ggdeploymentd/src/deployment_handler.c

+77-1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
#include <assert.h>
1515
#include <fcntl.h>
1616
#include <ggl/alloc.h>
17+
#include <ggl/backoff.h>
1718
#include <ggl/base64.h>
1819
#include <ggl/buffer.h>
1920
#include <ggl/bump_alloc.h>
@@ -409,6 +410,81 @@ static GglError get_tes_credentials(TesCredentials *tes_creds) {
409410
return GGL_ERR_OK;
410411
}
411412

413+
typedef struct CurlRequestRetryCtx {
414+
const char *url_for_sigv4_download;
415+
GglBuffer host;
416+
GglBuffer file_path;
417+
SigV4Details sigv4_details;
418+
419+
// reset response_data for next attempt
420+
GglError (*retry_cleanup_fn)(void *);
421+
void *response_data;
422+
423+
// Needed to propagate errors when retrying is impossible.
424+
GglError err;
425+
} DownloadRequestRetryCtx;
426+
427+
static GglError retry_download_wrapper(void *ctx) {
428+
DownloadRequestRetryCtx *retry_ctx = (DownloadRequestRetryCtx *) ctx;
429+
long http_response_code;
430+
431+
GglError ret = sigv4_download(
432+
retry_ctx->url_for_sigv4_download,
433+
retry_ctx->host,
434+
retry_ctx->file_path,
435+
*(int *) retry_ctx->response_data,
436+
retry_ctx->sigv4_details,
437+
&http_response_code
438+
);
439+
if (http_response_code == (long) 403) {
440+
GglError err = retry_ctx->retry_cleanup_fn(retry_ctx->response_data);
441+
if (err != GGL_ERR_OK) {
442+
retry_ctx->err = err;
443+
return GGL_ERR_OK;
444+
}
445+
return GGL_ERR_FAILURE;
446+
}
447+
if (ret != GGL_ERR_OK) {
448+
GGL_LOGE(
449+
"Artifact download attempt failed due to error: %d", ret
450+
451+
);
452+
retry_ctx->err = ret;
453+
return GGL_ERR_OK;
454+
}
455+
456+
retry_ctx->err = ret;
457+
return GGL_ERR_OK;
458+
}
459+
460+
static GglError retriable_download_request(
461+
const char *url_for_sigv4_download,
462+
GglBuffer host,
463+
GglBuffer file_path,
464+
int artifact_fd,
465+
SigV4Details sigv4_details
466+
) {
467+
DownloadRequestRetryCtx ctx
468+
= { .url_for_sigv4_download = url_for_sigv4_download,
469+
.host = host,
470+
.file_path = file_path,
471+
.sigv4_details = sigv4_details,
472+
.response_data = (void *) &artifact_fd,
473+
.retry_cleanup_fn = truncate_file,
474+
.err = GGL_ERR_OK };
475+
476+
GglError ret
477+
= ggl_backoff(1000, 64000, 3, retry_download_wrapper, (void *) &ctx);
478+
if (ret != GGL_ERR_OK) {
479+
GGL_LOGE("Artifact download attempt failed; retries exhausted.");
480+
return ret;
481+
}
482+
if (ctx.err != GGL_ERR_OK) {
483+
return ctx.err;
484+
}
485+
return GGL_ERR_OK;
486+
}
487+
412488
static GglError download_s3_artifact(
413489
GglBuffer scratch_buffer,
414490
GglUriInfo uri_info,
@@ -434,7 +510,7 @@ static GglError download_s3_artifact(
434510
return error;
435511
}
436512

437-
return sigv4_download(
513+
return retriable_download_request(
438514
(const char *) url_vec.buf.data,
439515
(GglBuffer) { .data = &scratch_buffer.data[start_loc],
440516
.len = end_loc - start_loc },

modules/ggl-file/include/ggl/file.h

+2
Original file line numberDiff line numberDiff line change
@@ -87,4 +87,6 @@ static inline void cleanup_closedir(DIR **dirp) {
8787
}
8888
}
8989

90+
GglError truncate_file(void *response_data);
91+
9092
#endif

modules/ggl-file/src/file.c

+15
Original file line numberDiff line numberDiff line change
@@ -578,3 +578,18 @@ GglError ggl_file_read_path(GglBuffer path, GglBuffer *content) {
578578

579579
return GGL_ERR_OK;
580580
}
581+
582+
GglError truncate_file(void *response_data) {
583+
int fd = *(int *) response_data;
584+
585+
int ret;
586+
do {
587+
ret = ftruncate(fd, 0);
588+
} while ((ret == -1) && (errno == EINTR));
589+
590+
if (ret == -1) {
591+
GGL_LOGE("Failed to truncate fd for write (errno=%d).", errno);
592+
return GGL_ERR_FAILURE;
593+
}
594+
return GGL_ERR_OK;
595+
}

modules/ggl-http/include/ggl/http.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,8 @@ GglError sigv4_download(
9898
GglBuffer host,
9999
GglBuffer file_path,
100100
int fd,
101-
SigV4Details sigv4_details
101+
SigV4Details sigv4_details,
102+
long *http_response_code
102103
);
103104

104105
GglError gg_dataplane_call(

modules/ggl-http/src/gghttp.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,8 @@ GglError sigv4_download(
7878
GglBuffer host,
7979
GglBuffer file_path,
8080
int fd,
81-
SigV4Details sigv4_details
81+
SigV4Details sigv4_details,
82+
long *http_response_code
8283
) {
8384
CurlData curl_data = { 0 };
8485
GglError error = gghttplib_init_curl(&curl_data, url_for_sigv4_download);
@@ -153,6 +154,7 @@ GglError sigv4_download(
153154
long http_status_code = 0;
154155
curl_easy_getinfo(curl_data.curl, CURLINFO_HTTP_CODE, &http_status_code);
155156
GGL_LOGD("Return HTTP code: %ld", http_status_code);
157+
*http_response_code = http_status_code;
156158

157159
struct curl_header *type = NULL;
158160
curl_easy_header(

modules/ggl-http/src/gghttp_util.c

-15
Original file line numberDiff line numberDiff line change
@@ -109,21 +109,6 @@ static GglError clear_buffer(void *response_data) {
109109
return GGL_ERR_OK;
110110
}
111111

112-
static GglError truncate_file(void *response_data) {
113-
int fd = *(int *) response_data;
114-
115-
int ret;
116-
do {
117-
ret = ftruncate(fd, 0);
118-
} while ((ret == -1) && (errno == EINTR));
119-
120-
if (ret == -1) {
121-
GGL_LOGE("Failed to truncate fd for write (errno=%d).", errno);
122-
return GGL_ERR_FAILURE;
123-
}
124-
return GGL_ERR_OK;
125-
}
126-
127112
static GglError curl_request_retry_wrapper(void *ctx) {
128113
CurlRequestRetryCtx *retry_ctx = (CurlRequestRetryCtx *) ctx;
129114
CurlData *curl_data = retry_ctx->curl_data;

0 commit comments

Comments
 (0)