Stop containers gracefully before remove instead of immediate SIGKILL.
Release rolling / release (push) Successful in 8m31s
Release rolling / release (push) Successful in 8m31s
This commit is contained in:
@@ -27,10 +27,11 @@ function isNoSuchContainer(err) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Release attachments that can delay Docker force-remove, then delete.
|
||||
* Release attachments that can delay Docker remove, stop the container, then delete.
|
||||
* Always stops first so processes shut down cleanly before removal.
|
||||
* @param {string} id
|
||||
* @param {import('../rpc/session.js').PeerSession} session
|
||||
* @param {{ force?: boolean, v?: boolean, removeVolumes?: boolean, link?: boolean }} args
|
||||
* @param {{ force?: boolean, v?: boolean, removeVolumes?: boolean, link?: boolean, timeout?: number, t?: number }} args
|
||||
*/
|
||||
async function forceRemoveContainer(id, session, args = {}) {
|
||||
session._cleanupLogsForContainer?.(id)
|
||||
@@ -49,14 +50,34 @@ async function forceRemoveContainer(id, session, args = {}) {
|
||||
}
|
||||
if (args.link) removeOpts.link = true
|
||||
|
||||
// SIGKILL first so remove does not wait on a stuck PID / long stop period
|
||||
if (force) {
|
||||
try {
|
||||
await container.kill({ signal: 'SIGKILL' })
|
||||
} catch (err) {
|
||||
// not running / already dead — fine
|
||||
if (!isNoSuchContainer(err) && !/is not running|already stopped/i.test(String(err?.message || ''))) {
|
||||
logger.debug('pre-remove kill skipped', { id: id.slice(0, 12), error: err?.message })
|
||||
// Stop first so the container shuts down cleanly before remove
|
||||
const stopTimeout =
|
||||
Number(args.timeout) >= 0
|
||||
? Number(args.timeout)
|
||||
: Number(args.t) >= 0
|
||||
? Number(args.t)
|
||||
: 10
|
||||
try {
|
||||
await container.stop({ t: stopTimeout })
|
||||
} catch (err) {
|
||||
// not running / already dead — fine
|
||||
if (!isNoSuchContainer(err) && !/is not running|already stopped/i.test(String(err?.message || ''))) {
|
||||
logger.debug('pre-remove stop skipped', { id: id.slice(0, 12), error: err?.message })
|
||||
// If force and stop failed unexpectedly, fall back to SIGKILL so remove can proceed
|
||||
if (force) {
|
||||
try {
|
||||
await container.kill({ signal: 'SIGKILL' })
|
||||
} catch (killErr) {
|
||||
if (
|
||||
!isNoSuchContainer(killErr) &&
|
||||
!/is not running|already stopped/i.test(String(killErr?.message || ''))
|
||||
) {
|
||||
logger.debug('pre-remove kill skipped', {
|
||||
id: id.slice(0, 12),
|
||||
error: killErr?.message,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user