swim: expose Lua triggers on member events
SWIM as a monitoring module is hard to use without an ability to subscribe on events. Otherwise a user should have polled a SWIM member table for updates - it would be too inefficient. This commit exposes an ability to set Lua triggers. Closes #4250 @TarantoolBot document Title: SWIM: swim:on_member_event Now a user can set triggers on member table updates. There is a function for that, which can be used in one of several ways: ```Lua swim:on_member_event(new_trigger[, ctx]) ``` Add a new trigger on member table update. The function `new_trigger` will be called on each new member appearance, an existing member drop, and update. It should take 3 arguments: first is an updated SWIM member, second is an events object, third is `ctx` passed as is. Events object has methods to help a user to determine what event has happened. ```Lua local function on_event(member, event, ctx) if event:is_new() then ... elseif event:is_drop() then ... end if event:is_update() then -- All next conditions can be -- true simultaneously. if event:is_new_status() then ... end if event:is_new_uri() then ... end if event:is_new_incarnation() then ... end if event:is_new_payload() then ... end end end s:on_member_event(on_event, ctx) ``` Note, that multiple events can happen simultaneously. A user should be ready to that. Additionally, 'new' and 'drop' never happen together. But they can happen with 'update', easily. Especially if there are lots of events, and triggers work too slow. Then a member can be added and updated after a while, but still does not reach a trigger. A remarkable case is 'new' + 'new payload'. This case does not correlate with triggers speed. The thing is that payload absence and payload of size 0 are not the same. And sometimes is happens, that a member is added without a payload. For example, a ping was received - pings do not carry payload. In such a case the missed payload is received later eventually. If that matters for a user's application, it should be ready to that: 'new' does not mean, that the member already has a payload, and payload size says nothing about its presence or absence. Second usage case: ```Lua swim:on_member_event(nil, old_trigger) ``` Drop an old trigger. Third usage case: ```Lua swim:on_member_event(new_trigger, old_trigger[, ctx]) ``` Replace an existing trigger in-place, with keeping its position in the trigger list. Fourth usage case: ```Lua swim:on_member_event() ``` Get a list of triggers. When drop or replace a trigger, a user should be attentive - the following code does not work: ```Lua tr = function() ... end -- Add a trigger. s:on_member_event(tr) ... -- Drop a trigger. s:on_member_event(nil, tr) ``` The last line, if be precise. This is because SWIM wraps user triggers with an internal closure for parameters preprocessing. To drop a trigger a user should save result of the first on_member_event() call. This code works: ```Lua tr = function() ... end -- Add a trigger. tr_id = s:on_member_event(tr) ... -- Drop a trigger. s:on_member_event(nil, tr_id) ``` The triggers are executed one by one in a separate fiber. And they can yield. These two facts mean that if one trigger sleeps too long - other triggers wait. It does not block SWIM from doing its routine operations, but block other triggers. The last point to remember is that if a member was added and dropped before its appearance has reached a trigger, then such a member does not fire triggers at all. A user will not notice that easy rider member.
Please register or sign in to comment