Skip to content
Snippets Groups Projects
  • Vladislav Shpilevoy's avatar
    6ee11c84
    swim: expose Lua triggers on member events · 6ee11c84
    Vladislav Shpilevoy authored
    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.
    6ee11c84
    History
    swim: expose Lua triggers on member events
    Vladislav Shpilevoy authored
    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.