Skip to content

Commit 2d5d07d

Browse files
committed
fix repeated shutdown issue on linux
motivation: repeatedly calling shutdown in linux was broken due to multiple calls to singal() which work on darwin but not linux changes: * conditionalize the call to signal * add test
1 parent 9a23b01 commit 2d5d07d

File tree

4 files changed

+45
-4
lines changed

4 files changed

+45
-4
lines changed

Sources/Lifecycle/Lifecycle.swift

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -343,13 +343,15 @@ extension ServiceLifecycle {
343343
/// - returns: a `DispatchSourceSignal` for the given trap. The source must be cancelled by the caller.
344344
public static func trap(signal sig: Signal, handler: @escaping (Signal) -> Void, on queue: DispatchQueue = .global(), cancelAfterTrap: Bool = false) -> DispatchSourceSignal {
345345
let signalSource = DispatchSource.makeSignalSource(signal: sig.rawValue, queue: queue)
346-
signal(sig.rawValue, SIG_IGN)
347-
signalSource.setEventHandler(handler: {
346+
signalSource.setEventHandler {
348347
if cancelAfterTrap {
349348
signalSource.cancel()
350349
}
351350
handler(sig)
352-
})
351+
}
352+
#if canImport(Darwin)
353+
signal(sig.rawValue, SIG_IGN)
354+
#endif
353355
signalSource.resume()
354356
return signalSource
355357
}

Tests/LifecycleTests/ServiceLifecycleTests+XCTest.swift

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ extension ServiceLifecycleTests {
3434
("testNesting2", testNesting2),
3535
("testSignalDescription", testSignalDescription),
3636
("testBacktracesInstalledOnce", testBacktracesInstalledOnce),
37+
("testRepeatShutdown", testRepeatShutdown),
3738
]
3839
}
3940
}

Tests/LifecycleTests/ServiceLifecycleTests.swift

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -233,4 +233,42 @@ final class ServiceLifecycleTests: XCTestCase {
233233
_ = ServiceLifecycle(configuration: config)
234234
_ = ServiceLifecycle(configuration: config)
235235
}
236+
237+
func testRepeatShutdown() {
238+
if ProcessInfo.processInfo.environment["SKIP_SIGNAL_TEST"].flatMap(Bool.init) ?? false {
239+
print("skipping testRepeatShutdown")
240+
return
241+
}
242+
243+
var count = 0
244+
245+
struct Service {
246+
static let signal = ServiceLifecycle.Signal.ALRM
247+
248+
let lifecycle: ServiceLifecycle
249+
250+
init() {
251+
self.lifecycle = ServiceLifecycle(configuration: .init(shutdownSignal: [Service.signal]))
252+
self.lifecycle.register(GoodItem())
253+
}
254+
}
255+
256+
func gracefulShutdown() {
257+
let service = Service()
258+
service.lifecycle.start { error in
259+
XCTAssertNil(error, "not expecting error")
260+
kill(getpid(), Service.signal.rawValue)
261+
}
262+
263+
service.lifecycle.wait()
264+
count = count + 1 // not thread safe but fine for this purpose
265+
}
266+
267+
let attempts = Int.random(in: 2 ..< 5)
268+
for _ in 0 ..< attempts {
269+
gracefulShutdown()
270+
}
271+
272+
XCTAssertEqual(attempts, count)
273+
}
236274
}

docker/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ RUN apt-get update && apt-get install -y lsof dnsutils netcat-openbsd net-tools
2020
RUN apt-get update && apt-get install -y ruby ruby-dev libsqlite3-dev build-essential
2121
# switch of gem docs building
2222
RUN echo "gem: --no-document" > ~/.gemrc
23-
RUN if [ "${ubuntu_version}" != "xenial" ] ; then gem install jazzy ; fi
23+
RUN if [ "${ubuntu_version}" != "xenial" ] ; then gem install jazzy -v 0.13.7 ; fi
2424

2525
# tools
2626
RUN mkdir -p $HOME/.tools

0 commit comments

Comments
 (0)