diff options
| author | William Boman <william@redwill.se> | 2022-12-05 02:35:40 +0100 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-12-05 02:35:40 +0100 |
| commit | 0b60344d4b648027ceb657dcd03aed9c3bfa8b58 (patch) | |
| tree | b2c890659f96107745a22df1f6efc4b603bf94db | |
| parent | feat: show warning message when exiting neovim with active installations (#725) (diff) | |
| download | mason-0b60344d4b648027ceb657dcd03aed9c3bfa8b58.tar mason-0b60344d4b648027ceb657dcd03aed9c3bfa8b58.tar.gz mason-0b60344d4b648027ceb657dcd03aed9c3bfa8b58.tar.bz2 mason-0b60344d4b648027ceb657dcd03aed9c3bfa8b58.tar.lz mason-0b60344d4b648027ceb657dcd03aed9c3bfa8b58.tar.xz mason-0b60344d4b648027ceb657dcd03aed9c3bfa8b58.tar.zst mason-0b60344d4b648027ceb657dcd03aed9c3bfa8b58.zip | |
feat(terminator): send SIGKILL after some delay after SIGTERM (#727)
Give a very generous grace period for processes to terminate gracefully
before forcefully killing them, to ensure none linger.
| -rw-r--r-- | lua/mason/init.lua | 2 | ||||
| -rw-r--r-- | lua/mason/terminator.lua | 45 | ||||
| -rw-r--r-- | tests/mason/terminator_spec.lua | 37 |
3 files changed, 57 insertions, 27 deletions
diff --git a/lua/mason/init.lua b/lua/mason/init.lua index f6c46ef4..62a66bea 100644 --- a/lua/mason/init.lua +++ b/lua/mason/init.lua @@ -16,7 +16,7 @@ local function setup_autocmds() vim.api.nvim_create_autocmd("VimLeavePre", { callback = function() - require("mason.terminator").terminate() + require("mason.terminator").terminate(5000) end, once = true, }) diff --git a/lua/mason/terminator.lua b/lua/mason/terminator.lua index 7a9290a0..ea4bd5a2 100644 --- a/lua/mason/terminator.lua +++ b/lua/mason/terminator.lua @@ -22,21 +22,32 @@ local M = {} ---@async ---@param handles InstallHandle[] -local function terminate_handles(handles) +---@param grace_ms integer +local function terminate_handles(handles, grace_ms) a.wait_all(vim.tbl_map( ---@param handle InstallHandle function(handle) - if not handle:is_closed() then - handle:terminate() - end return function() - a.wait(function(resolve) - if handle:is_closed() then - resolve() - else - handle:once("closed", resolve) - end - end) + a.wait_first { + function() + if not handle:is_closed() then + handle:terminate() + end + a.wait(function(resolve) + if handle:is_closed() then + resolve() + else + handle:once("closed", resolve) + end + end) + end, + function() + a.sleep(grace_ms) + if not handle:is_closed() then + handle:kill(9) -- SIGKILL + end + end, + } end end, handles @@ -57,7 +68,8 @@ function M.setup() end) end -function M.terminate() +---@param grace_ms integer +function M.terminate(grace_ms) local handles = vim.tbl_keys(active_handles) if #handles > 0 then local package_names = vim.tbl_map(function(h) @@ -76,14 +88,7 @@ function M.terminate() -- 2. Synchronously terminate all installation handles. a.run_blocking(function() - a.wait_first { - function() - a.sleep(5000) - end, - function() - terminate_handles(handles) - end, - } + terminate_handles(handles, grace_ms) end) -- 3. Schedule error message to be displayed so that Neovim prints it to the tty. diff --git a/tests/mason/terminator_spec.lua b/tests/mason/terminator_spec.lua index 9f243086..2058d4e2 100644 --- a/tests/mason/terminator_spec.lua +++ b/tests/mason/terminator_spec.lua @@ -1,4 +1,5 @@ local stub = require "luassert.stub" +local match = require "luassert.match" local spy = require "luassert.spy" local a = require "mason-core.async" local registry = require "mason-registry" @@ -14,6 +15,7 @@ describe("terminator", function() it( "should terminate all active handles on nvim exit", async_test(function() + spy.on(InstallHandle, "terminate") local dummy = registry.get_package "dummy" local dummy2 = registry.get_package "dummy2" for _, pkg in ipairs { dummy, dummy2 } do @@ -25,11 +27,9 @@ describe("terminator", function() dummy:install() dummy2:install() - spy.on(InstallHandle, "terminate") + terminator.terminate(5000) - terminator.terminate() a.scheduler() - assert.spy(InstallHandle.terminate).was_called(2) end) ) @@ -39,6 +39,7 @@ describe("terminator", function() async_test(function() spy.on(vim.api, "nvim_echo") spy.on(vim.api, "nvim_err_writeln") + spy.on(InstallHandle, "terminate") local dummy = registry.get_package "dummy" local dummy2 = registry.get_package "dummy2" for _, pkg in ipairs { dummy, dummy2 } do @@ -50,9 +51,7 @@ describe("terminator", function() dummy:install() dummy2:install() - spy.on(InstallHandle, "terminate") - - terminator.terminate() + terminator.terminate(5000) assert.spy(vim.api.nvim_echo).was_called(1) assert.spy(vim.api.nvim_echo).was_called_with({ @@ -72,4 +71,30 @@ describe("terminator", function() ]]) end) ) + + it( + "should send SIGTERM and then SIGKILL after grace period", + async_test(function() + spy.on(InstallHandle, "kill") + local dummy = registry.get_package "dummy" + stub(dummy.spec, "install") + dummy.spec.install.invokes(function(ctx) + -- your signals have no power here + ctx.spawn.bash { "-c", "function noop { :; }; trap noop SIGTERM; sleep 999999;" } + end) + + local handle = dummy:install() + + assert.wait_for(function() + assert.spy(dummy.spec.install).was_called() + end) + terminator.terminate(50) + + assert.wait_for(function() + assert.spy(InstallHandle.kill).was_called(2) + assert.spy(InstallHandle.kill).was_called_with(match.is_ref(handle), 15) -- SIGTERM + assert.spy(InstallHandle.kill).was_called_with(match.is_ref(handle), 9) -- SIGKILL + end) + end) + ) end) |
