Skip to content

Commit

Permalink
Add mark_left function (#68)
Browse files Browse the repository at this point in the history
  • Loading branch information
yngvar-antonsson authored Jan 13, 2025
1 parent f5b67f0 commit 6d30c9e
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 0 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,18 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.

## [Unreleased]

### Added

- `mark_left` function to mark removed members as `left`.

## [2.4.5] - 2024-06-24

### Fixed

- Invalid events parsing.

## [2.4.4] - 2024-04-09

### Fixed

- Invalid payload parsing in anti entropy step.
Expand Down
34 changes: 34 additions & 0 deletions membership.lua
Original file line number Diff line number Diff line change
Expand Up @@ -736,6 +736,39 @@ local function leave()
return true
end

--- Forcefully send leave message about an instance.
-- @function mark_left
-- @treturn boolean
-- `true` if call succeeds,
-- `false` if member has already left.
local function mark_left(uri_to_leave)
if _sock == nil then
return false
end

-- Perform artificial events.generate() and instantly send it
local myself = members.get(uri_to_leave)
if not myself or myself.status == opts.LEFT then
return false
end
local event = events.pack({
uri = uri_to_leave,
status = opts.LEFT,
incarnation = myself.incarnation,
ttl = members.count(),
})
local msg_msgpacked = msgpack.encode({uri_to_leave, 'LEAVE', msgpack.NULL, {event}})
local msg_encrypted = opts.encrypt(msg_msgpacked)
for _, uri in ipairs(members.filter_excluding('unhealthy', uri_to_leave)) do
local addr = resolve(uri)
if addr then
_sock:sendto(addr.host, addr.port, msg_encrypted)
end
end

return true
end

--- Member data structure.
-- A member is represented by the table with the following fields:
--
Expand Down Expand Up @@ -984,6 +1017,7 @@ end
return {
init = init,
leave = leave,
mark_left = mark_left,
members = get_members,
broadcast = broadcast,
pairs = function() return pairs(get_members()) end,
Expand Down
12 changes: 12 additions & 0 deletions test/test_quit.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,15 @@ def test_rejoin(servers, helpers):
assert servers[13302].conn.eval('return membership.init("localhost", 13302)')[0]
assert servers[13301].add_member('localhost:13302')
helpers.wait_for(servers[13301].check_status, ['localhost:13302', 'alive'])


def test_mark_left(servers, helpers):
helpers.wait_for(servers[13301].check_status, ['localhost:13302', 'alive'])
assert servers[13301].conn.eval('return membership.mark_left("localhost:13302")')[0]
helpers.wait_for(servers[13301].check_status, ['localhost:13302', 'left'])

# already has left
assert not servers[13301].conn.eval('return membership.mark_left("localhost:13302")')[0]

# there are no such member
assert not servers[13301].conn.eval('return membership.mark_left("localhost:10000")')[0]

0 comments on commit 6d30c9e

Please sign in to comment.