MEDIUM: mailers: Init alerts during conf parsing and refactor their processing
Email alerts relies on checks to send emails. The link between a mailers section
and a proxy was resolved during the configuration parsing, But initialization was
done when the first alert is triggered. This implied memory allocations and
tasks creations. With this patch, everything is now initialized during the
configuration parsing. So when an alert is triggered, only the memory required
by this alert is dynamically allocated.
Moreover, alerts processing had a flaw. The task handler used to process alerts
to be sent to the same mailer, process_email_alert, was designed to give back
the control to the scheduler when an alert was sent. So there was a delay
between the sending of 2 consecutives alerts (the min of
"proxy->timeout.connect" and "mailer->timeout.mail"). To fix this problem, now,
we try to process as much queued alerts as possible when the task is woken up.
diff --git a/include/proto/checks.h b/include/proto/checks.h
index 853daad..98dca25 100644
--- a/include/proto/checks.h
+++ b/include/proto/checks.h
@@ -24,6 +24,7 @@
#include <types/task.h>
#include <common/config.h>
+#include <types/mailers.h>
const char *get_check_status_description(short check_status);
const char *get_check_status_info(short check_status);
@@ -46,6 +47,7 @@
const char *init_check(struct check *check, int type);
void free_check(struct check *check);
+int init_email_alert(struct mailers *mailers, struct proxy *p, char **err);
void send_email_alert(struct server *s, int priority, const char *format, ...)
__attribute__ ((format(printf, 3, 4)));
int srv_check_healthcheck_port(struct check *chk);
diff --git a/include/types/proxy.h b/include/types/proxy.h
index 5306a3b..1130f2f 100644
--- a/include/types/proxy.h
+++ b/include/types/proxy.h
@@ -228,6 +228,7 @@
struct email_alert {
struct list list;
struct list tcpcheck_rules;
+ struct server *srv;
};
struct email_alertq {
diff --git a/src/cfgparse.c b/src/cfgparse.c
index 8b1d8f8..4db59a3 100644
--- a/src/cfgparse.c
+++ b/src/cfgparse.c
@@ -7948,20 +7948,23 @@
struct mailers *curmailers = mailers;
for (curmailers = mailers; curmailers; curmailers = curmailers->next) {
- if (strcmp(curmailers->id, curproxy->email_alert.mailers.name) == 0) {
- free(curproxy->email_alert.mailers.name);
- curproxy->email_alert.mailers.m = curmailers;
- curmailers->users++;
+ if (!strcmp(curmailers->id, curproxy->email_alert.mailers.name))
break;
- }
}
-
if (!curmailers) {
Alert("Proxy '%s': unable to find mailers '%s'.\n",
curproxy->id, curproxy->email_alert.mailers.name);
free_email_alert(curproxy);
cfgerr++;
}
+ else {
+ err = NULL;
+ if (init_email_alert(curmailers, curproxy, &err)) {
+ Alert("Proxy '%s': %s.\n", curproxy->id, err);
+ free(err);
+ cfgerr++;
+ }
+ }
}
if (curproxy->uri_auth && !(curproxy->uri_auth->flags & ST_CONVDONE) &&
diff --git a/src/checks.c b/src/checks.c
index d9c3393..6972f9c 100644
--- a/src/checks.c
+++ b/src/checks.c
@@ -37,7 +37,6 @@
#include <common/time.h>
#include <types/global.h>
-#include <types/mailers.h>
#include <types/dns.h>
#include <types/stats.h>
@@ -3051,95 +3050,117 @@
static struct task *process_email_alert(struct task *t)
{
- struct check *check = t->context;
+ struct check *check = t->context;
struct email_alertq *q;
+ struct email_alert *alert;
q = container_of(check, typeof(*q), check);
- if (!(check->state & CHK_ST_ENABLED)) {
- if (LIST_ISEMPTY(&q->email_alerts)) {
- /* All alerts processed, delete check */
- task_delete(t);
- task_free(t);
- check->task = NULL;
- return NULL;
- } else {
- struct email_alert *alert;
+ while (1) {
+ if (!(check->state & CHK_ST_ENABLED)) {
+ if (LIST_ISEMPTY(&q->email_alerts)) {
+ /* All alerts processed, queue the task */
+ t->expire = TICK_ETERNITY;
+ task_queue(t);
+ return t;
+ }
alert = LIST_NEXT(&q->email_alerts, typeof(alert), list);
- check->tcpcheck_rules = &alert->tcpcheck_rules;
LIST_DEL(&alert->list);
-
- check->state |= CHK_ST_ENABLED;
+ t->expire = now_ms;
+ check->server = alert->srv;
+ check->tcpcheck_rules = &alert->tcpcheck_rules;
+ check->status = HCHK_STATUS_INI;
+ check->state |= CHK_ST_ENABLED;
}
- }
-
- process_chk(t);
-
- if (!(check->state & CHK_ST_INPROGRESS) && check->tcpcheck_rules) {
- struct email_alert *alert;
+ process_chk(t);
+ if (check->state & CHK_ST_INPROGRESS)
+ break;
alert = container_of(check->tcpcheck_rules, typeof(*alert), tcpcheck_rules);
email_alert_free(alert);
-
check->tcpcheck_rules = NULL;
- check->state &= ~CHK_ST_ENABLED;
+ check->server = NULL;
+ check->state &= ~CHK_ST_ENABLED;
}
return t;
}
-static int init_email_alert_checks(struct server *s)
+/* Initializes mailer alerts for the proxy <p> using <mls> parameters.
+ *
+ * The function returns 1 in success case, otherwise, it returns 0 and err is
+ * filled.
+ */
+int init_email_alert(struct mailers *mls, struct proxy *p, char **err)
{
- int i;
- struct mailer *mailer;
- const char *err_str;
- struct proxy *p = s->proxy;
-
- if (p->email_alert.queues)
- /* Already initialised, nothing to do */
- return 1;
+ struct mailer *mailer;
+ struct email_alertq *queues;
+ const char *err_str;
+ int i = 0;
- p->email_alert.queues = calloc(p->email_alert.mailers.m->count, sizeof *p->email_alert.queues);
- if (!p->email_alert.queues) {
- err_str = "out of memory while allocating checks array";
- goto error_alert;
+ if ((queues = calloc(mls->count, sizeof(*queues))) == NULL) {
+ memprintf(err, "out of memory while allocating mailer alerts queues");
+ goto error;
}
- for (i = 0, mailer = p->email_alert.mailers.m->mailer_list;
- i < p->email_alert.mailers.m->count; i++, mailer = mailer->next) {
- struct email_alertq *q = &p->email_alert.queues[i];
- struct check *check = &q->check;
-
+ for (mailer = mls->mailer_list; mailer; i++, mailer = mailer->next) {
+ struct email_alertq *q = &queues[i];
+ struct check *check = &q->check;
+ struct task *t;
LIST_INIT(&q->email_alerts);
- check->inter = p->email_alert.mailers.m->timeout.mail;
+ check->inter = mls->timeout.mail;
check->rise = DEF_AGENT_RISETIME;
check->fall = DEF_AGENT_FALLTIME;
- err_str = init_check(check, PR_O2_TCPCHK_CHK);
- if (err_str) {
- goto error_free;
+ if ((err_str = init_check(check, PR_O2_TCPCHK_CHK))) {
+ memprintf(err, "%s", err_str);
+ goto error;
}
check->xprt = mailer->xprt;
+ check->addr = mailer->addr;
if (!get_host_port(&mailer->addr))
/* Default to submission port */
check->port = 587;
- check->addr = mailer->addr;
- check->server = s;
- }
+ //check->server = s;
- return 1;
+ if ((t = task_new()) == NULL) {
+ memprintf(err, "out of memory while allocating mailer alerts task");
+ goto error;
+ }
+
+ check->task = t;
+ t->process = process_email_alert;
+ t->context = check;
-error_free:
- while (i-- > 1)
- task_free(p->email_alert.queues[i].check.task);
- free(p->email_alert.queues);
- p->email_alert.queues = NULL;
-error_alert:
- Alert("Email alert [%s] could not be initialised: %s\n", p->id, err_str);
+ /* check this in one ms */
+ t->expire = TICK_ETERNITY;
+ check->start = now;
+ task_queue(t);
+ }
+
+ mls->users++;
+ free(p->email_alert.mailers.name);
+ p->email_alert.mailers.m = mls;
+ p->email_alert.queues = queues;
return 0;
+
+ error:
+ for (i = 0; i < mls->count; i++) {
+ struct email_alertq *q = &queues[i];
+ struct check *check = &q->check;
+
+ if (check->task) {
+ task_delete(check->task);
+ task_free(check->task);
+ check->task = NULL;
+ }
+ free_check(check);
+ }
+ free(queues);
+ return 1;
}
@@ -3194,19 +3215,19 @@
return 1;
}
-static int enqueue_one_email_alert(struct email_alertq *q, const char *msg)
+static int enqueue_one_email_alert(struct proxy *p, struct server *s,
+ struct email_alertq *q, const char *msg)
{
struct email_alert *alert = NULL;
struct tcpcheck_rule *tcpcheck;
struct check *check = &q->check;
- struct proxy *p = check->server->proxy;
alert = calloc(1, sizeof *alert);
if (!alert) {
goto error;
}
LIST_INIT(&alert->tcpcheck_rules);
-
+ alert->srv = s;
tcpcheck = calloc(1, sizeof *tcpcheck);
if (!tcpcheck)
goto error;
@@ -3289,24 +3310,8 @@
if (!add_tcpcheck_expect_str(&alert->tcpcheck_rules, "221 "))
goto error;
- if (!check->task) {
- struct task *t;
-
- if ((t = task_new()) == NULL)
- goto error;
-
- check->task = t;
- t->process = process_email_alert;
- t->context = check;
-
- /* check this in one ms */
- t->expire = tick_add(now_ms, MS_TO_TICKS(1));
- check->start = now;
- task_queue(t);
- }
-
+ task_wakeup(check->task, TASK_WOKEN_MSG);
LIST_ADDQ(&q->email_alerts, &alert->list);
-
return 1;
error:
@@ -3314,14 +3319,14 @@
return 0;
}
-static void enqueue_email_alert(struct proxy *p, const char *msg)
+static void enqueue_email_alert(struct proxy *p, struct server *s, const char *msg)
{
int i;
struct mailer *mailer;
for (i = 0, mailer = p->email_alert.mailers.m->mailer_list;
i < p->email_alert.mailers.m->count; i++, mailer = mailer->next) {
- if (!enqueue_one_email_alert(&p->email_alert.queues[i], msg)) {
+ if (!enqueue_one_email_alert(p, s, &p->email_alert.queues[i], msg)) {
Alert("Email alert [%s] could not be enqueued: out of memory\n", p->id);
return;
}
@@ -3340,8 +3345,7 @@
int len;
struct proxy *p = s->proxy;
- if (!p->email_alert.mailers.m || level > p->email_alert.level ||
- format == NULL || !init_email_alert_checks(s))
+ if (!p->email_alert.mailers.m || level > p->email_alert.level || format == NULL)
return;
va_start(argp, format);
@@ -3353,7 +3357,7 @@
return;
}
- enqueue_email_alert(p, buf);
+ enqueue_email_alert(p, s, buf);
}
/*