File tree Expand file tree Collapse file tree 4 files changed +35
-5
lines changed Expand file tree Collapse file tree 4 files changed +35
-5
lines changed Original file line number Diff line number Diff line change @@ -41,6 +41,17 @@ public enum Lambda {
41
41
var logger = logger
42
42
do {
43
43
while !Task. isCancelled {
44
+
45
+ if let runtimeClient = runtimeClient as? LambdaRuntimeClient ,
46
+ let futureConnectionClosed = await runtimeClient. futureConnectionClosed
47
+ {
48
+ // Wait for the futureConnectionClosed to complete,
49
+ // which will happen when the Lambda HTTP Server (or MockServer) closes the connection
50
+ // This allows us to exit the run loop gracefully.
51
+ // The futureConnectionClosed is always an error, let it throw to finish the run loop.
52
+ let _ = try await futureConnectionClosed. get ( )
53
+ }
54
+
44
55
let ( invocation, writer) = try await runtimeClient. nextInvocation ( )
45
56
logger[ metadataKey: " aws-request-id " ] = " \( invocation. metadata. requestID) "
46
57
@@ -84,6 +95,7 @@ public enum Lambda {
84
95
} catch is CancellationError {
85
96
// don't allow cancellation error to propagate further
86
97
}
98
+
87
99
}
88
100
89
101
/// The default EventLoop the Lambda is scheduled on.
Original file line number Diff line number Diff line change @@ -17,8 +17,14 @@ import ServiceLifecycle
17
17
18
18
extension LambdaRuntime : Service {
19
19
public func run( ) async throws {
20
- try await cancelWhenGracefulShutdown {
21
- try await self . _run ( )
20
+ await cancelWhenGracefulShutdown {
21
+ do {
22
+ try await self . _run ( )
23
+ } catch {
24
+ // catch top level error that have not been handled before
25
+ // this avoids the runtime to crash and generate a backtrace
26
+ self . logger. error ( " LambdaRuntime.run() failed with error " , metadata: [ " error " : " \( error) " ] )
27
+ }
22
28
}
23
29
}
24
30
}
Original file line number Diff line number Diff line change @@ -59,7 +59,13 @@ public final class LambdaRuntime<Handler>: Sendable where Handler: StreamingLamb
59
59
#if !ServiceLifecycleSupport
60
60
@inlinable
61
61
internal func run( ) async throws {
62
- try await _run ( )
62
+ do {
63
+ try await _run ( )
64
+ } catch {
65
+ // catch top level error that have not been handled before
66
+ // this avoids the runtime to crash and generate a backtrace
67
+ self . logger. error ( " LambdaRuntime.run() failed with error " , metadata: [ " error " : " \( error) " ] )
68
+ }
63
69
}
64
70
#endif
65
71
Original file line number Diff line number Diff line change @@ -92,6 +92,9 @@ final actor LambdaRuntimeClient: LambdaRuntimeClientProtocol {
92
92
case closed
93
93
}
94
94
95
+ @usableFromInline
96
+ var futureConnectionClosed : EventLoopFuture < LambdaRuntimeError > ? = nil
97
+
95
98
private let eventLoop : any EventLoop
96
99
private let logger : Logger
97
100
private let configuration : Configuration
@@ -372,8 +375,10 @@ final actor LambdaRuntimeClient: LambdaRuntimeClientProtocol {
372
375
// however, this happens when performance testing against the MockServer
373
376
// shutdown this runtime.
374
377
// The Lambda service will create a new runtime environment anyway
375
- runtimeClient. logger. trace ( " Connection to Lambda API lost, exiting " )
376
- exit ( - 1 )
378
+ runtimeClient. logger. trace ( " Connection to Lambda API. lost, exiting " )
379
+ runtimeClient. futureConnectionClosed = runtimeClient. eventLoop. makeFailedFuture (
380
+ LambdaRuntimeError ( code: . connectionToControlPlaneLost)
381
+ )
377
382
}
378
383
}
379
384
@@ -392,6 +397,7 @@ final actor LambdaRuntimeClient: LambdaRuntimeClientProtocol {
392
397
return handler
393
398
}
394
399
} catch {
400
+
395
401
switch self . connectionState {
396
402
case . disconnected, . connected:
397
403
fatalError ( " Unexpected state: \( self . connectionState) " )
You can’t perform that action at this time.
0 commit comments