libobs: Improve exponential backoff functionality

- Changes the default base exponent value to 1.5 from 2.0
- Applies a random skew of +-0.05 to the exponent to lessen the
"water hammer" effect caused by predictable backoff techniques
- Fixes the logging associated with exponential backoff to log the
true reconnect delay value
master
tt2468 2022-06-25 16:19:48 -07:00
parent 7475eff13a
commit bb55cfbc05
2 changed files with 20 additions and 12 deletions

View File

@ -1027,7 +1027,8 @@ struct obs_output {
int reconnect_retry_sec; int reconnect_retry_sec;
int reconnect_retry_max; int reconnect_retry_max;
int reconnect_retries; int reconnect_retries;
int reconnect_retry_cur_sec; uint64_t reconnect_retry_cur_msec;
float reconnect_retry_exp;
pthread_t reconnect_thread; pthread_t reconnect_thread;
os_event_t *reconnect_stop_event; os_event_t *reconnect_stop_event;
volatile bool reconnecting; volatile bool reconnecting;

View File

@ -18,6 +18,7 @@
#include <inttypes.h> #include <inttypes.h>
#include "util/platform.h" #include "util/platform.h"
#include "util/util_uint64.h" #include "util/util_uint64.h"
#include "graphics/math-extra.h"
#include "obs.h" #include "obs.h"
#include "obs-internal.h" #include "obs-internal.h"
@ -26,6 +27,9 @@
#define get_weak(output) ((obs_weak_output_t *)output->context.control) #define get_weak(output) ((obs_weak_output_t *)output->context.control)
#define RECONNECT_RETRY_MAX_MSEC (15 * 60 * 1000)
#define RECONNECT_RETRY_BASE_EXP 1.5
static inline bool active(const struct obs_output *output) static inline bool active(const struct obs_output *output)
{ {
return os_atomic_load_bool(&output->active); return os_atomic_load_bool(&output->active);
@ -145,6 +149,8 @@ obs_output_t *obs_output_create(const char *id, const char *name,
output->reconnect_retry_sec = 2; output->reconnect_retry_sec = 2;
output->reconnect_retry_max = 20; output->reconnect_retry_max = 20;
output->reconnect_retry_exp =
RECONNECT_RETRY_BASE_EXP + (rand_float(0) * 0.05);
output->valid = true; output->valid = true;
obs_context_init_control(&output->context, output, obs_context_init_control(&output->context, output,
@ -1968,7 +1974,7 @@ static inline void signal_reconnect(struct obs_output *output)
calldata_init_fixed(&params, stack, sizeof(stack)); calldata_init_fixed(&params, stack, sizeof(stack));
calldata_set_int(&params, "timeout_sec", calldata_set_int(&params, "timeout_sec",
output->reconnect_retry_cur_sec); output->reconnect_retry_cur_msec / 1000);
calldata_set_ptr(&params, "output", output); calldata_set_ptr(&params, "output", output);
signal_handler_signal(output->context.signals, "reconnect", &params); signal_handler_signal(output->context.signals, "reconnect", &params);
} }
@ -2351,11 +2357,11 @@ void obs_output_end_data_capture(obs_output_t *output)
static void *reconnect_thread(void *param) static void *reconnect_thread(void *param)
{ {
struct obs_output *output = param; struct obs_output *output = param;
unsigned long ms = output->reconnect_retry_cur_sec * 1000;
output->reconnect_thread_active = true; output->reconnect_thread_active = true;
if (os_event_timedwait(output->reconnect_stop_event, ms) == ETIMEDOUT) if (os_event_timedwait(output->reconnect_stop_event,
output->reconnect_retry_cur_msec) == ETIMEDOUT)
obs_output_actual_start(output); obs_output_actual_start(output);
if (os_event_try(output->reconnect_stop_event) == EAGAIN) if (os_event_try(output->reconnect_stop_event) == EAGAIN)
@ -2367,14 +2373,13 @@ static void *reconnect_thread(void *param)
return NULL; return NULL;
} }
#define MAX_RETRY_SEC (15 * 60)
static void output_reconnect(struct obs_output *output) static void output_reconnect(struct obs_output *output)
{ {
int ret; int ret;
if (!reconnecting(output)) { if (!reconnecting(output)) {
output->reconnect_retry_cur_sec = output->reconnect_retry_sec; output->reconnect_retry_cur_msec =
output->reconnect_retry_sec * 1000;
output->reconnect_retries = 0; output->reconnect_retries = 0;
} }
@ -2393,9 +2398,10 @@ static void output_reconnect(struct obs_output *output)
} }
if (output->reconnect_retries) { if (output->reconnect_retries) {
output->reconnect_retry_cur_sec *= 2; output->reconnect_retry_cur_msec *= output->reconnect_retry_exp;
if (output->reconnect_retry_cur_sec > MAX_RETRY_SEC) if (output->reconnect_retry_cur_msec > RECONNECT_RETRY_MAX_MSEC)
output->reconnect_retry_cur_sec = MAX_RETRY_SEC; output->reconnect_retry_cur_msec =
RECONNECT_RETRY_MAX_MSEC;
} }
output->reconnect_retries++; output->reconnect_retries++;
@ -2407,8 +2413,9 @@ static void output_reconnect(struct obs_output *output)
blog(LOG_WARNING, "Failed to create reconnect thread"); blog(LOG_WARNING, "Failed to create reconnect thread");
os_atomic_set_bool(&output->reconnecting, false); os_atomic_set_bool(&output->reconnecting, false);
} else { } else {
blog(LOG_INFO, "Output '%s': Reconnecting in %d seconds..", blog(LOG_INFO, "Output '%s': Reconnecting in %.02f seconds..",
output->context.name, output->reconnect_retry_sec); output->context.name,
(float)(output->reconnect_retry_cur_msec / 1000.0));
signal_reconnect(output); signal_reconnect(output);
} }