vapor icon indicating copy to clipboard operation
vapor copied to clipboard

Clarify what's the best way to shutdown a Vapor server from a route handler

Open MaxDesiatov opened this issue 3 years ago • 7 comments

Is your feature request related to a problem? Please describe. Calling shutdown() on an Application instance from a route handler or a WebSocket handler leads to this assertion:

Precondition failed: BUG DETECTED: wait() must not be called when on an EventLoop.
Calling wait() on any EventLoop can lead to
- deadlocks
- stalling processing of other connections (Channels) that are handled on the EventLoop that wait was called on

Further information:
- current eventLoop: Optional(SelectableEventLoop { selector = Selector { descriptor = 16 }, thread = NIOThread(name = NIO-ELT-0-#7), scheduledTasks = PriorityQueue(count: 1): [ScheduledTask(readyTime: 79776511569019)] })
- event loop associated to future: SelectableEventLoop { selector = Selector { descriptor = 6 }, thread = NIOThread(name = NIO-ELT-0-#3) }: file /Users/maxd/Documents/carton/.build/checkouts/vapor/Sources/Vapor/HTTP/Server/HTTPServer.swift, line 282

Describe the solution you'd like Provide a documented way to trigger server shutdown from a route handler or a WebSocket handler.

Describe alternatives you've considered kill(getpid(), SIGINT) works, but seems to be quite hacky.

Additional context This is needed to implement https://github.com/swiftwasm/carton/pull/173 cleanly. We have a build tool for SwiftWasm that fetches the Wasm binary from a Vapor server, runs it, then connects via WebSocket and to report results of the run. The server should then shutdown when notified via a WebSocket handler.

MaxDesiatov avatar Nov 22 '20 21:11 MaxDesiatov

How about using this?

app.get("pleaseShutdown") { (request: Request) -> String in
	let app = request.application
	DispatchQueue.global().asyncAfter(deadline: .now() + 2) {
		app.running?.stop()
	}

	return "Shutdown initiated."
}

klaas avatar Nov 27 '20 11:11 klaas

.now() + 2 seems arbitrary here? Also, why global queue? Application is a class instance, which is not thread-safe I guess?

MaxDesiatov avatar Nov 27 '20 11:11 MaxDesiatov

I pretty much looked at ServeCommand.swift and mirrored what happens when I press ctrl-c in the command line.

2 seconds is arbitrary.

I'm just using it for development purposes and it works fine for me. Triggered within Xcode by a Keyboard Maestro shortcut.

+1 for clarifying what the recommended way would be 😃

klaas avatar Nov 28 '20 09:11 klaas

Using terminal:

lsof  -i:[PORT_NUMBER]

sudo kill -9 [PORT_NUMBER]

lalkrishna avatar Aug 24 '22 10:08 lalkrishna

In an iOS app, app.shutdown() works. But my question is how to restart it?

trevor-sonic avatar Mar 19 '24 17:03 trevor-sonic

@trevor-sonic once you've shut down the app, you essentially have a fresh Application you can start in the same way as you originally started it

0xTim avatar Mar 25 '24 04:03 0xTim