#include <proto/arg.h>
#include <proto/backend.h>
#include <proto/filters.h>
+#include <proto/freq_ctr.h>
#include <proto/frontend.h>
#include <proto/log.h>
#include <proto/proto_http.h>
/* Helper to get ctx inside an appctx */
#define APPCTX_SPOE(appctx) ((appctx)->ctx.spoe)
-/* TODO: add an option to customize these values */
-/* The maximum number of new applet waiting the end of the hello handshake */
-#define MAX_NEW_SPOE_APPLETS 5
-
-/* The maximum number of error when a stream is waiting of a SPOE applet */
-#define MAX_NEW_SPOE_APPLET_ERRS 3
-
/* Minimal size for a frame */
#define MIN_FRAME_SIZE 256
char *var_pfx; /* Prefix used for vars set by the agent */
unsigned int flags; /* SPOE_FL_* */
+ unsigned int cps_max; /* Maximum number of connections per second */
+ unsigned int eps_max; /* Maximum number of errors per second */
struct list cache; /* List used to cache SPOE streams. In
* fact, we cache the SPOE applect ctx */
* for each supported events */
struct list applet_wq; /* List of streams waiting for a SPOE applet */
- unsigned int new_applets; /* The number of new SPOE applets */
+ struct freq_ctr conn_per_sec; /* connections per second */
+ struct freq_ctr err_per_sec; /* connetion errors per second */
};
/* SPOE filter configuration */
struct list buffer_wait; /* position in the list of streams waiting for a buffer */
struct list applet_wait; /* position in the list of streams waiting for a SPOE applet */
- unsigned int errs; /* The number of errors to acquire a SPOE applet */
-
enum spoe_ctx_state state; /* SPOE_CTX_ST_* */
unsigned int flags; /* SPOE_CTX_FL_* */
si_applet_cant_get(&strm->si[0]);
appctx_wakeup(appctx);
- /* Increase the number of applets waiting the end of the hello
- * handshake. */
- conf->agent->new_applets++;
+ /* Increase the per-process number of cumulated connections */
+ if (conf->agent->cps_max > 0)
+ update_freq_ctr(&conf->agent->conn_per_sec, 1);
strm->do_log = NULL;
strm->res.flags |= CF_READ_DONTWAIT;
{
struct spoe_context *ctx;
- agent->new_applets--;
list_for_each_entry(ctx, &agent->applet_wq, applet_wait) {
- ctx->errs++;
task_wakeup(ctx->strm->task, TASK_WOKEN_MSG);
SPOE_PRINTF(stderr, "%d.%06d [SPOE/%-15s] %s: stream=%p"
" - wake up stream because to SPOE applet connection failed\n",
static void
on_new_spoe_appctx_success(struct spoe_agent *agent, struct appctx *appctx)
{
- agent->new_applets--;
offer_spoe_appctx(agent, appctx);
}
/* Retrieve a SPOE applet from the agent cache if possible, else create it. It
goto success;
}
- /* If there is no server up for the agent's backend or it too many
- * failure occurred, this is an error. */
- if ((!agent->b.be->srv_act && !agent->b.be->srv_bck) ||
- ctx->errs >= MAX_NEW_SPOE_APPLET_ERRS)
+ /* If there is no server up for the agent's backend, this is an
+ * error. */
+ if (!agent->b.be->srv_act && !agent->b.be->srv_bck)
goto error;
SPOE_PRINTF(stderr, "%d.%06d [SPOE/%-15s] %s: stream=%p"
LIST_ADDQ(&agent->applet_wq, &ctx->applet_wait);
/* Finally, create new SPOE applet if we can */
- if (agent->new_applets < MAX_NEW_SPOE_APPLETS) {
- if (create_spoe_appctx(conf) == NULL)
- goto error;
+ if (agent->cps_max > 0) {
+ if (!freq_ctr_remain(&agent->conn_per_sec, agent->cps_max, 0))
+ goto wait;
}
+ if (create_spoe_appctx(conf) == NULL)
+ goto error;
wait:
return 0;
ctx->flags |= ((dir == SMP_OPT_DIR_REQ)
? SPOE_CTX_FL_REQ_PROCESS
: SPOE_CTX_FL_RSP_PROCESS);
- ctx->errs = 0;
SPOE_PRINTF(stderr, "%d.%06d [SPOE/%-15s] %s: stream=%p"
" - acquire SPOE appctx %p from cache\n",
}
SPOE_PRINTF(stderr, "%d.%06d [SPOE/%-15s] %s: stream=%p"
- " - failed to acquire SPOE appctx errs=%u\n",
+ " - failed to acquire SPOE appctx\n",
(int)now.tv_sec, (int)now.tv_usec, agent->id,
- __FUNCTION__, ctx->strm, ctx->errs);
+ __FUNCTION__, ctx->strm);
send_log(ctx->strm->be, LOG_WARNING, "failed to acquire SPOE applet.\n");
return -1;
agent->id, __FUNCTION__, s, spoe_ctx_state_str[ctx->state],
spoe_event_str[ev]);
+ if (agent->eps_max > 0) {
+ if (!freq_ctr_remain(&agent->err_per_sec, agent->eps_max, 0)) {
+ SPOE_PRINTF(stderr, "%d.%06d [SPOE/%-15s] %s: stream=%p"
+ " - skip event '%s': max EPS reached\n",
+ (int)now.tv_sec, (int)now.tv_usec,
+ agent->id, __FUNCTION__, s, spoe_event_str[ev]);
+ goto skip;
+ }
+ }
+
dir = ((ev < SPOE_EV_ON_SERVER_SESS) ? SMP_OPT_DIR_REQ : SMP_OPT_DIR_RES);
if (LIST_ISEMPTY(&(ctx->messages[ev])))
return 1;
error:
+ if (agent->eps_max > 0)
+ update_freq_ctr(&agent->err_per_sec, 1);
+
release_spoe_appctx(ctx);
ctx->state = ((agent->flags & SPOE_FL_CONT_ON_ERR)
? SPOE_CTX_ST_READY
ctx->filter = filter;
ctx->state = SPOE_CTX_ST_NONE;
ctx->flags = 0;
- ctx->errs = 0;
ctx->messages = conf->agent->messages;
ctx->buffer = &buf_empty;
LIST_INIT(&ctx->buffer_wait);
curagent->timeout.processing = TICK_ETERNITY;
curagent->var_pfx = NULL;
curagent->flags = 0;
- curagent->new_applets = 0;
+ curagent->cps_max = 0;
+ curagent->eps_max = 0;
for (i = 0; i < SPOE_EV_EVENTS; ++i)
LIST_INIT(&curagent->messages[i]);
else if (!strcmp(args[1], "continue-on-error")) {
if (*args[2]) {
Alert("parsing [%s:%d] : cannot handle unexpected argument '%s'.\n",
- file, linenum, args[3]);
+ file, linenum, args[2]);
err_code |= ERR_ALERT | ERR_ABORT;
goto out;
}
goto out;
}
}
+ else if (!strcmp(args[0], "maxconnrate")) {
+ if (!*args[1]) {
+ Alert("parsing [%s:%d] : '%s' expects an integer argument.\n",
+ file, linenum, args[0]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+ if (*args[2]) {
+ Alert("parsing [%s:%d] : cannot handle unexpected argument '%s'.\n",
+ file, linenum, args[2]);
+ err_code |= ERR_ALERT | ERR_ABORT;
+ goto out;
+ }
+ curagent->cps_max = atol(args[1]);
+ }
+ else if (!strcmp(args[0], "maxerrrate")) {
+ if (!*args[1]) {
+ Alert("parsing [%s:%d] : '%s' expects an integer argument.\n",
+ file, linenum, args[0]);
+ err_code |= ERR_ALERT | ERR_FATAL;
+ goto out;
+ }
+ if (*args[2]) {
+ Alert("parsing [%s:%d] : cannot handle unexpected argument '%s'.\n",
+ file, linenum, args[2]);
+ err_code |= ERR_ALERT | ERR_ABORT;
+ goto out;
+ }
+ curagent->eps_max = atol(args[1]);
+ }
else if (*args[0]) {
Alert("parsing [%s:%d] : unknown keyword '%s' in spoe-agent section.\n",
file, linenum, args[0]);