Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add an Option to disable retries #694

Merged
merged 13 commits into from
Nov 13, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletions include/aws/io/retry_strategy.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,13 +106,13 @@ enum aws_exponential_backoff_jitter_mode {
* "use defaults"
*/
struct aws_exponential_backoff_retry_options {
/** Event loop group to use for scheduling tasks. */
/* Event loop group to use for scheduling tasks. */
struct aws_event_loop_group *el_group;
/** Max retries to allow. The default value is 10 */
/* Max retries to allow. The default value is 10 */
size_t max_retries;
/** Scaling factor to add for the backoff. Default is 500ms */
/* Scaling factor to add for the backoff. Default is 500ms */
uint32_t backoff_scale_factor_ms;
/** Max retry backoff in seconds. Default is 20 seconds */
/* Max retry backoff in seconds. Default is 20 seconds */
uint32_t max_backoff_secs;
/** Jitter mode to use, see comments for aws_exponential_backoff_jitter_mode.
* Default is AWS_EXPONENTIAL_BACKOFF_JITTER_DEFAULT */
Expand All @@ -139,6 +139,14 @@ struct aws_exponential_backoff_retry_options {
const struct aws_shutdown_callback_options *shutdown_options;
};

struct aws_no_retry_options {
/**
* Optional shutdown callback that gets invoked, with appropriate user data,
* when the resources used by the retry_strategy are no longer in use.
*/
const struct aws_shutdown_callback_options *shutdown_options;
};

struct aws_standard_retry_options {
struct aws_exponential_backoff_retry_options backoff_retry_options;
/** capacity for partitions. Defaults to 500 */
Expand Down Expand Up @@ -235,6 +243,16 @@ AWS_IO_API struct aws_retry_strategy *aws_retry_strategy_new_standard(
struct aws_allocator *allocator,
const struct aws_standard_retry_options *config);

/**
* This retry strategy is used to disable retries. Passed config can be null.
* Calling `aws_retry_strategy_acquire_retry_token` will raise error `AWS_IO_RETRY_PERMISSION_DENIED`.
* Calling any function apart from the `aws_retry_strategy_acquire_retry_token` and `aws_retry_strategy_release` will
* result in a fatal error.
*/
AWS_IO_API struct aws_retry_strategy *aws_retry_strategy_new_no_retry(
struct aws_allocator *allocator,
const struct aws_no_retry_options *config);

AWS_EXTERN_C_END
AWS_POP_SANE_WARNING_LEVEL

Expand Down
85 changes: 85 additions & 0 deletions source/no_retry_strategy.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <aws/common/ref_count.h>
#include <aws/io/io.h>
#include <aws/io/retry_strategy.h>

struct aws_retry_strategy_no_retries {
struct aws_retry_strategy base;
struct aws_shutdown_callback_options shutdown_options;
};

static void s_no_retry_destroy(struct aws_retry_strategy *retry_strategy) {
if (retry_strategy) {
struct aws_retry_strategy_no_retries *strategy = retry_strategy->impl;
aws_simple_completion_callback *completion_callback = strategy->shutdown_options.shutdown_callback_fn;
void *completion_user_data = strategy->shutdown_options.shutdown_callback_user_data;

aws_mem_release(retry_strategy->allocator, strategy);
if (completion_callback != NULL) {
completion_callback(completion_user_data);
}
}
}

static int s_no_retry_acquire_token(
struct aws_retry_strategy *retry_strategy,
const struct aws_byte_cursor *partition_id,
aws_retry_strategy_on_retry_token_acquired_fn *on_acquired,
void *user_data,
uint64_t timeout_ms) {
(void)retry_strategy;
(void)partition_id;
(void)on_acquired;
(void)user_data;
(void)timeout_ms;
return aws_raise_error(AWS_IO_RETRY_PERMISSION_DENIED);
}

static int s_no_retry_schedule_retry(
struct aws_retry_token *token,
enum aws_retry_error_type error_type,
aws_retry_strategy_on_retry_ready_fn *retry_ready,
void *user_data) {
(void)token;
(void)error_type;
(void)retry_ready;
(void)user_data;
AWS_FATAL_ASSERT(0 && "schedule_retry must not be called for no_retries retry strategy");
}

static int s_no_retry_record_success(struct aws_retry_token *token) {
(void)token;
AWS_FATAL_ASSERT(0 && "record_success must not be called for no_retries retry strategy");
}

static void s_no_retry_release_token(struct aws_retry_token *token) {
(void)token;
AWS_FATAL_ASSERT(0 && "release_token must not be called for no_retries retry strategy");
}

static struct aws_retry_strategy_vtable s_exponential_retry_vtable = {
.destroy = s_no_retry_destroy,
.acquire_token = s_no_retry_acquire_token,
.schedule_retry = s_no_retry_schedule_retry,
.record_success = s_no_retry_record_success,
.release_token = s_no_retry_release_token,
};

struct aws_retry_strategy *aws_retry_strategy_new_no_retry(
struct aws_allocator *allocator,
const struct aws_no_retry_options *config) {
struct aws_retry_strategy_no_retries *strategy =
aws_mem_calloc(allocator, 1, sizeof(struct aws_retry_strategy_no_retries));
strategy->base.allocator = allocator;
strategy->base.impl = strategy;
strategy->base.vtable = &s_exponential_retry_vtable;
aws_atomic_init_int(&strategy->base.ref_count, 1);

if (config != NULL && config->shutdown_options) {
strategy->shutdown_options = *config->shutdown_options;
}
return &strategy->base;
}
1 change: 1 addition & 0 deletions tests/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ add_test_case(test_exponential_backoff_retry_client_errors_do_not_count)
add_test_case(test_exponential_backoff_retry_no_jitter_time_taken)
add_test_case(test_exponential_max_backoff_retry_no_jitter)
add_test_case(test_exponential_backoff_retry_invalid_options)
add_test_case(test_no_retries)

add_test_case(test_standard_retry_strategy_setup_shutdown)
add_test_case(test_standard_retry_strategy_failure_exhausts_bucket)
Expand Down
27 changes: 27 additions & 0 deletions tests/no_retry_strategy_test.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
/**
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
* SPDX-License-Identifier: Apache-2.0.
*/
#include <aws/io/io.h>
#include <aws/io/retry_strategy.h>
#include <aws/testing/aws_test_harness.h>

static int s_test_no_retries_fn(struct aws_allocator *allocator, void *ctx) {
(void)ctx;

aws_io_library_init(allocator);

struct aws_retry_strategy *retry_strategy = aws_retry_strategy_new_no_retry(allocator, NULL);
ASSERT_NOT_NULL(retry_strategy);

ASSERT_ERROR(
AWS_IO_RETRY_PERMISSION_DENIED, aws_retry_strategy_acquire_retry_token(retry_strategy, NULL, NULL, NULL, 0));

aws_retry_strategy_release(retry_strategy);

aws_io_library_clean_up();

return AWS_OP_SUCCESS;
}

AWS_TEST_CASE(test_no_retries, s_test_no_retries_fn)