@@ -80,41 +80,49 @@ public enum Lambda {
8080 @discardableResult
8181 internal static func run( configuration: Configuration = . init( ) , factory: @escaping ( EventLoop ) throws -> Handler ) -> Result < Int , Error > {
8282 self . run ( configuration: configuration, factory: { eventloop -> EventLoopFuture < Handler > in
83- do {
84- let handler = try factory ( eventloop)
85- return eventloop. makeSucceededFuture ( handler)
86- } catch {
87- return eventloop. makeFailedFuture ( error)
83+ let promise = eventloop. makePromise ( of: Handler . self)
84+ // if we have a callback based handler factory, we offload the creation of the handler
85+ // onto the default offload queue, to ensure that the eventloop is never blocked.
86+ Lambda . defaultOffloadQueue. async {
87+ do {
88+ promise. succeed ( try factory ( eventloop) )
89+ } catch {
90+ promise. fail ( error)
91+ }
8892 }
93+ return promise. futureResult
8994 } )
9095 }
9196
9297 // for testing and internal use
9398 @discardableResult
9499 internal static func run( configuration: Configuration = . init( ) , factory: @escaping HandlerFactory ) -> Result < Int , Error > {
95- do {
96- let eventLoopGroup = MultiThreadedEventLoopGroup ( numberOfThreads: 1 ) // only need one thread, will improve performance
97- defer { try ! eventLoopGroup. syncShutdownGracefully ( ) }
98- let result = try self . runAsync ( eventLoopGroup: eventLoopGroup, configuration: configuration, factory: factory) . wait ( )
99- return . success( result)
100- } catch {
101- return . failure( error)
102- }
103- }
104-
105- internal static func runAsync( eventLoopGroup: EventLoopGroup , configuration: Configuration , factory: @escaping HandlerFactory ) -> EventLoopFuture < Int > {
106100 Backtrace . install ( )
107101 var logger = Logger ( label: " Lambda " )
108102 logger. logLevel = configuration. general. logLevel
109- let lifecycle = Lifecycle ( eventLoop: eventLoopGroup. next ( ) , logger: logger, configuration: configuration, factory: factory)
110- let signalSource = trap ( signal: configuration. lifecycle. stopSignal) { signal in
111- logger. info ( " intercepted signal: \( signal) " )
112- lifecycle. shutdown ( )
113- }
114- return lifecycle. start ( ) . flatMap {
115- return lifecycle. shutdownFuture. always { _ in
103+
104+ var result : Result < Int , Error > !
105+ MultiThreadedEventLoopGroup . withCurrentThreadAsEventLoop { eventLoop in
106+ let lifecycle = Lifecycle ( eventLoop: eventLoop, logger: logger, configuration: configuration, factory: factory)
107+ let signalSource = trap ( signal: configuration. lifecycle. stopSignal) { signal in
108+ logger. info ( " intercepted signal: \( signal) " )
109+ lifecycle. shutdown ( )
110+ }
111+
112+ lifecycle. start ( ) . flatMap {
113+ lifecycle. shutdownFuture
114+ } . whenComplete { lifecycleResult in
116115 signalSource. cancel ( )
116+ eventLoop. shutdownGracefully { error in
117+ if let error = error {
118+ preconditionFailure ( " Failed to shutdown eventloop: \( error) " )
119+ }
120+ }
121+ result = lifecycleResult
117122 }
118123 }
124+
125+ logger. info ( " shutdown completed " )
126+ return result
119127 }
120128}
0 commit comments