-
Notifications
You must be signed in to change notification settings - Fork 80
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
[DRAFT] Share circuit breakers between workers #227
base: implement_lru_cache
Are you sure you want to change the base?
Changes from 36 commits
e74c999
e89c2c5
bb0e96e
1d04c0c
3d78bbe
e20c078
569a551
f55e521
f517f75
7c0fc80
7325b47
3c45b3f
35217ae
7ba1e9e
8e64bd0
def383d
efb62a9
7474bed
203cdfd
f251c8f
128788f
5bb4d65
f6bcf7f
3498109
e4631b0
effaea6
bff9225
0ae9c55
26aa0dd
43f6a57
dafe362
63495a9
13763b1
e2f8a5d
efd72d0
d16c6ab
ddd7268
0a00e94
4682bed
f43ccbf
af854a5
6445222
3e04a43
3655ae8
926074d
05796e7
be44b32
d3f252c
ea78022
9fb115a
286b6c1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
#include "circuit_breaker.h" | ||
|
||
#include "sysv_semaphores.h" | ||
#include "sysv_shared_memory.h" | ||
#include "types.h" | ||
#include "util.h" | ||
|
||
void | ||
semian_circuit_breaker_free(void* ptr) | ||
{ | ||
semian_circuit_breaker_t* res = (semian_circuit_breaker_t*)ptr; | ||
free_shared_memory(res->shmem); | ||
} | ||
|
||
size_t | ||
semian_circuit_breaker_size(const void* ptr) | ||
{ | ||
return sizeof(semian_circuit_breaker_t); | ||
} | ||
|
||
static const rb_data_type_t semian_circuit_breaker_type = { | ||
.wrap_struct_name = "semian_circuit_breaker", | ||
.function = { | ||
.dmark = NULL, | ||
.dfree = semian_circuit_breaker_free, | ||
.dsize = semian_circuit_breaker_size, | ||
}, | ||
.data = NULL, | ||
.flags = RUBY_TYPED_FREE_IMMEDIATELY, | ||
}; | ||
|
||
void | ||
Init_CircuitBreaker() { | ||
dprintf("Init_CircuitBreaker"); | ||
|
||
VALUE cSemian = rb_const_get(rb_cObject, rb_intern("Semian")); | ||
VALUE cCircuitBreaker = rb_const_get(cSemian, rb_intern("CircuitBreaker")); | ||
|
||
rb_define_alloc_func(cCircuitBreaker, semian_circuit_breaker_alloc); | ||
rb_define_method(cCircuitBreaker, "initialize_circuit_breaker", semian_circuit_breaker_initialize, 2); | ||
} | ||
|
||
VALUE | ||
semian_circuit_breaker_alloc(VALUE klass) | ||
{ | ||
semian_circuit_breaker_t *res; | ||
VALUE obj = TypedData_Make_Struct(klass, semian_circuit_breaker_t, &semian_circuit_breaker_type, res); | ||
return obj; | ||
} | ||
|
||
VALUE | ||
semian_circuit_breaker_initialize(VALUE self, VALUE name) | ||
{ | ||
semian_circuit_breaker_t *res = NULL; | ||
TypedData_Get_Struct(self, semian_circuit_breaker_t, &semian_circuit_breaker_type, res); | ||
|
||
char buffer[1024]; | ||
strcpy(buffer, to_s(name)); | ||
strcat(buffer, "_circuit_breaker"); | ||
res->key = generate_key(buffer); | ||
|
||
dprintf("Initializing circuit breaker '%s' (key: %lu)", buffer, res->key); | ||
res->sem_id = initialize_single_semaphore(res->key, SEM_DEFAULT_PERMISSIONS); | ||
res->shmem = get_or_create_shared_memory(res->key, NULL); | ||
|
||
return self; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
#ifndef CIRCUIT_BREAKER_H | ||
#define CIRCUIT_BREAKER_H | ||
|
||
#include <ruby.h> | ||
|
||
void Init_CircuitBreaker(); | ||
|
||
VALUE semian_circuit_breaker_alloc(VALUE klass); | ||
VALUE semian_circuit_breaker_initialize(VALUE self, VALUE id); | ||
VALUE semian_circuit_breaker_successes(VALUE self); | ||
|
||
#endif // CIRCUIT_BREAKER_H |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,5 +1,7 @@ | ||
#include "semian.h" | ||
|
||
static int use_c_circuits(); | ||
|
||
void Init_semian() | ||
{ | ||
VALUE cSemian, cResource; | ||
|
@@ -64,4 +66,30 @@ void Init_semian() | |
|
||
/* Maximum number of tickets available on this system. */ | ||
rb_define_const(cSemian, "MAX_TICKETS", INT2FIX(system_max_semaphore_count)); | ||
|
||
if (use_c_circuits()) { | ||
Init_SimpleInteger(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why did you choose to override them rather than define them and switch at the Ruby-layer instead? The latter seems a bit cleaner to me. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Mostly because that's roughly the way the bulkhead was implemented, and I wanted to keep the codebase familiar. One could argue that the Ruby implementation of the bulkhead is actually just a stub, but then those functions should have There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Fine with me. 👍 |
||
Init_SlidingWindow(); | ||
Init_CircuitBreaker(); | ||
} | ||
} | ||
|
||
static int | ||
use_c_circuits() { | ||
char *circuit_impl = getenv("SEMIAN_CIRCUIT_BREAKER_IMPL"); | ||
if (circuit_impl == NULL) { | ||
fprintf(stderr, "Warning: Defaulting to worker-based circuit breaker implementation\n"); | ||
return 0; | ||
} else { | ||
if (!strcmp(circuit_impl, "worker")) { | ||
return 0; | ||
} else if (!strcmp(circuit_impl, "host")) { | ||
return 1; | ||
} else { | ||
fprintf(stderr, "Warning: Unknown circuit breaker implementation: '%s'\n", circuit_impl); | ||
return 0; | ||
} | ||
} | ||
|
||
rb_raise(rb_eArgError, "Unknown circuit breaker implementation"); | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is really tough advice to give someone. That can be days to weeks of work. Can we, with our simulation tooling, provide some sample values that we can include here? I imagine we can generate a somewhat magic constant based on simulations on (1)
ss_error_rate
steady-state error rates, (2)n
number of Semian consumers (threads * workers), (3)error_threshold
, (4)resource_timeout
, (5) whatever other inputs you all use?I'd like the advice to then be something along the lines of...