]> git.kaiwu.me - haproxy.git/commitdiff
MINOR: hlua: expose PROXY event family through Lua
authorAurelien DARRAGON <adarragon@haproxy.com>
Wed, 7 Oct 2026 10:42:43 +0000 (12:42 +0200)
committerAurelien DARRAGON <adarragon@haproxy.com>
Mon, 12 Oct 2026 07:50:14 +0000 (09:50 +0200)
Add Proxy.event_sub() method to be able to subscribe to per proxy events,
and expose PROXY event family through Lua event_hdl handler.

Documentation was updated with known PROXY family events (ADD/DEL/
PUB/UNPUB).

doc/lua-api/index.rst
src/hlua.c
src/hlua_fcn.c

index 8632aaf6a19ae8238cae5c29a50d3450ef57fe4e..20364e79a8aabd3fb8b73884447e0950e51402aa 100644 (file)
@@ -1056,6 +1056,13 @@ instances being inherited by the proxies using them. See the
      (e.g.: SERVER_STATE will always be generated for each SERVER_DOWN or
      SERVER_UP)
 
+   **PROXY** Family:
+
+    * **PROXY_ADD**: when a proxy is added dynamically
+    * **PROXY_DEL**: when a server is removed dynamically
+    * **PROXY_PUB**: when a proxy is published (ready to serve connections)
+    * **PROXY_UNPUB**: when a server is unpublished (ineligible for trafic)
+
   The prototype of the Lua function used as argument is:
 
 .. code-block:: lua
@@ -1067,7 +1074,8 @@ instances being inherited by the proxies using them. See the
     when subscribing)
   * **event_data**: specific to each event family (For **SERVER** family,
     a :ref:`server_event_class` object; for **ACME** family,
-    a :ref:`acme_event_class` object)
+    a :ref:`acme_event_class` object, for **PROXY** family,
+    a :ref:`proxy_event_class` object)
   * **sub**: class to manage the subscription from within the event
     (a :ref:`event_sub_class` object)
   * **when**: timestamp corresponding to the date when the event was generated.
@@ -1256,6 +1264,59 @@ Proxy class
    proxy.
   :returns: a :ref:`proxy_mailers_class` containing proxy mailers config
 
+.. js:function:: Proxy.event_sub(px, event_types, func)
+
+  Register a function that will be called on specific proxy events.
+  It works exactly like :js:func:`core.event_sub()` except that the subscription
+  will be performed within the proxy dedicated subscription list instead of the
+  global one.
+  (Your callback function will only be called for proxy events affecting px)
+
+  See :js:func:`core.event_sub()` for function usage.
+
+  A key advantage to using :js:func:`Proxy.event_sub()` over
+  :js:func:`core.event_sub()` for proxies is that :js:func:`Proxy.event_sub()`
+  allows you to be notified for proxies events of a single proxy only.
+  It removes the needs for extra filtering in your callback function if you only
+  care about a single proxy, and also prevents useless wakeups.
+
+  .. Note::
+     You may also combine :js:func:`core.event_sub()` with
+     :js:func:`Proxy.event_sub()`.
+
+     Also, don't forget that you can use :js:func:`core.register_task()` from
+     your callback function if needed. (ie: parallel work)
+
+  Here is a working example combining :js:func:`core.event_sub()` with
+  :js:func:`Proxy.event_sub()` and :js:func:`core.register_task()`
+  (This only serves as a demo, this is not necessarily useful to do so)
+
+.. code-block:: lua
+
+  core.event_sub({"PROXY_ADD"}, function(event, data, sub)
+    -- in the global event handler
+    if data["reference"] ~= nil then
+      print("Tracking new proxy: ", data["name"])
+      data["reference"]:event_sub({"PROXY_PUB", "PROXY_UNPUB"}, function(event, data, sub)
+        -- in the per-proxy event handler
+       if data["reference"] ~= nil then
+          core.register_task(function(proxy)
+            -- subtask to perform some async work (e.g.: HTTP API calls, sending emails...)
+            print("ASYNC: PROXY ", proxy:get_name(), " is ", event == "PROXY_PUB" and "PUBLISHED" or "UNPUBLISHED")
+          end, data["reference"])
+        end
+      end)
+    end
+  end)
+
+..
+
+  In this example, we will first track global proxy addition events.
+  For each newly added proxy ("add backend" on the cli), we will register a
+  PUB, UNPUB proxy subscription.
+  Then, the callback function will schedule the event handling in an async
+  subtask which will receive the server reference as an argument.
+
 .. _proxy_mailers_class:
 
 ProxyMailers class
index 46d7cc96e62f6816a229a1cc60661b94739f8275..c62b952b4bf2679a9aa4e12e8cef4ac3f0f176dc 100644 (file)
@@ -9576,6 +9576,39 @@ __LJMP static void hlua_event_hdl_cb_push_args(struct hlua_event_sub *hlua_sub,
                        }
                }
        }
+       else if (event_hdl_sub_family_equal(EVENT_HDL_SUB_PROXY, event)) {
+               struct event_hdl_cb_data_proxy *e_proxy = data;
+               struct proxy *px;
+
+               hlua->nargs += 1;
+               lua_newtable(hlua->T);
+               /* Add proxy name */
+               lua_pushstring(hlua->T, "name");
+               lua_pushstring(hlua->T, e_proxy->safe.name);
+               lua_settable(hlua->T, -3);
+               /* Add proxy uuid */
+               lua_pushstring(hlua->T, "uuid");
+               lua_pushinteger(hlua->T, e_proxy->safe.uuid);
+               lua_settable(hlua->T, -3);
+               /* Add proxy cap */
+               lua_pushstring(hlua->T, "cap");
+               lua_pushstring(hlua->T, proxy_cap_str(e_proxy->safe.cap));
+               lua_settable(hlua->T, -3);
+               /* Add server proxy guid */
+               lua_pushstring(hlua->T, "guid");
+               lua_pushstring(hlua->T, e_proxy->safe.guid);
+               lua_settable(hlua->T, -3);
+
+               /* attempt to provide reference proxy object
+                * (if it wasn't removed yet, PROXY_DEL will never succeed here)
+                */
+               px = proxy_find_by_id(e_proxy->safe.uuid, e_proxy->safe.cap, 0);
+               if (px) {
+                       lua_pushstring(hlua->T, "reference");
+                       hlua_fcn_new_proxy(hlua->T, px);
+                       lua_settable(hlua->T, -3);
+               }
+       }
 #if defined(HAVE_ACME)
        else if (event_hdl_sub_family_equal(EVENT_HDL_SUB_ACME, event)) {
                MAY_LJMP(acme_hlua_event_push_args(hlua, event, data));
index 44f37b1996b31c99711067f57618e14976ea7c56..5a53e52123c899c9b577853a9ea242aaa12d12b8 100644 (file)
@@ -2254,6 +2254,27 @@ int hlua_proxy_get_mailers(lua_State *L)
        return 1;
 }
 
+/* hlua_event_sub wrapper for per-proxy subscription:
+ *
+ * hlua_event_sub() is called with proxy->e_subs subscription list and
+ * lua arguments are passed as-is (skipping the first argument which
+ * is the proxy ctx)
+ */
+int hlua_proxy_event_sub(lua_State *L)
+{
+       struct proxy *px;
+
+       px = hlua_check_proxy(L, 1);
+       if (px == NULL) {
+               return 0;
+       }
+       /* remove first argument from the stack (proxy) */
+       lua_remove(L, 1);
+
+       /* try to subscribe within proxy's subscription list */
+       return hlua_event_sub(L, &px->e_subs);
+}
+
 int hlua_fcn_new_proxy(lua_State *L, struct proxy *px)
 {
        struct listener *lst;
@@ -2284,6 +2305,7 @@ int hlua_fcn_new_proxy(lua_State *L, struct proxy *px)
        hlua_class_function(L, "get_srv_bck", hlua_proxy_get_srv_bck);
        hlua_class_function(L, "get_stats", hlua_proxy_get_stats);
        hlua_class_function(L, "get_mailers", hlua_proxy_get_mailers);
+       hlua_class_function(L, "event_sub", hlua_proxy_event_sub);
 
        /* Browse and register servers. */
        lua_pushstring(L, "servers");