]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
EXAMPLES: mailqueue for lua mailers script
authorAurelien DARRAGON <adarragon@haproxy.com>
Wed, 3 May 2023 17:12:53 +0000 (19:12 +0200)
committerChristopher Faulet <cfaulet@haproxy.com>
Fri, 5 May 2023 14:28:32 +0000 (16:28 +0200)
Lua mailers scripts now leverages Queue class to implement a mailqueue.

Thanks to the mailqueue, emails are still sent asynchronously, but with
respect to their generation order (better ordering consistency).

That is, previous script limitation (see below) is no longer true:
"
 Current known script limitation: if multiple events are generated
 simultaneously it is possible that emails could be received out of
 order since emails are sent asynchronously using smtp_send_email()
 and there is no sending queue. Relying on the email "date" should
 help to know which email was generated first..
"

For a given server, email-alerts will be sent in the same order as the
events were generated. However this does not apply to events between 2
distinct servers, since each server is tracked independently within
the lua script. (1 subscription per server, to make sure only relevant
servers x events are being tracked and prevent useless wakeups)

examples/lua/mailers.lua

index cbc8205aa5791e03e0660cc492b48fdcd81605f4..e36800b73fed8b6d10ed00be0ea0800264020777 100644 (file)
@@ -16,6 +16,8 @@ local SYSLOG_LEVEL = {
        ["DEBUG"] = 7
 }
 
+local mailqueue = core.queue()
+
 -- smtp : send SMTP message
 --
 -- Copyright 2018 Thierry Fournier
@@ -140,28 +142,16 @@ local function send_email_alert(srv, level, message, when)
                return
        end
 
-       -- email sending is performed asynchronously
-       core.register_task(function(mailers, msg, when)
-               for name, mailsrv in pairs(mailers.mailservers) do
-                       local mailsrv_ip, mailsrv_port = string.match(mailsrv, "([^:]+):([^:]+)")
-                       local date = os.date("%a, %d %b %Y %T %z (%Z)", when)
-                       local c = core.concat()
+       -- email sending is performed asynchronously thanks to mailqueue
+       local job = {}
 
-                       c:add(string.format("From: %s\r\n", mailers.smtp_from))
-                       c:add(string.format("To: %s\r\n", mailers.smtp_to))
-                       c:add(string.format("Date: %s\r\n", date))
-                       c:add(string.format("Subject: [HAProxy Alert] %s\r\n", msg))
-                       c:add("\r\n")
-                       c:add(string.format("%s\r\n", msg))
+       job.mailconf = mailers
+       job.when = when
+       job.msg = message
+
+       -- enqueue email job
+       mailqueue:push(job)
 
-                       local ret, reason = smtp_send_email(mailsrv_ip, mailsrv_port,
-                                                           mailers.smtp_hostname, mailers.smtp_from,
-                                                           mailers.smtp_to, c:dump())
-                       if ret == false then
-                               core.Warning("Can't send email: " .. reason)
-                       end
-                       end
-       end, mailers, message, when)
 end
 
 local function srv_get_check_details(check)
@@ -389,3 +379,40 @@ core.register_task(function()
        end
 
 end)
+
+-- mail queue
+core.register_task(function()
+       while true
+       do
+               local job = mailqueue:pop_wait()
+
+               if job ~= nil then
+                       local date = os.date("%a, %d %b %Y %T %z (%Z)", job.when)
+                       local c = core.concat()
+
+                       -- prepare email body
+                       c:add(string.format("From: %s\r\n", job.mailconf.smtp_from))
+                       c:add(string.format("To: %s\r\n", job.mailconf.smtp_to))
+                       c:add(string.format("Date: %s\r\n", date))
+                       c:add(string.format("Subject: [HAProxy Alert] %s\r\n", job.msg))
+                       c:add("\r\n")
+                       c:add(string.format("%s\r\n", job.msg))
+
+                       -- send email to all mailservers
+                       for name, mailsrv in pairs(job.mailconf.mailservers) do
+                               -- split mailsrv (ip:port) in 2 variables
+                               local mailsrv_ip, mailsrv_port = string.match(mailsrv, "([^:]+):([^:]+)")
+
+                               -- finally, send email to server
+                               local ret, reason = smtp_send_email(mailsrv_ip, mailsrv_port,
+                                                                   job.mailconf.smtp_hostname,
+                                                                   job.mailconf.smtp_from,
+                                                                   job.mailconf.smtp_to,
+                                                                   c:dump())
+                               if ret == false then
+                                       core.Warning("Can't send email alert to ".. name .. ": " .. reason)
+                               end
+                       end
+               end
+       end
+end)