Skip to content

Commit 166cd46

Browse files
committed
propagate the connection closed info through a Future
1 parent 6e01c6e commit 166cd46

File tree

4 files changed

+35
-5
lines changed

4 files changed

+35
-5
lines changed

Sources/AWSLambdaRuntime/Lambda.swift

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,17 @@ public enum Lambda {
4141
var logger = logger
4242
do {
4343
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+
4455
let (invocation, writer) = try await runtimeClient.nextInvocation()
4556
logger[metadataKey: "aws-request-id"] = "\(invocation.metadata.requestID)"
4657

@@ -84,6 +95,7 @@ public enum Lambda {
8495
} catch is CancellationError {
8596
// don't allow cancellation error to propagate further
8697
}
98+
8799
}
88100

89101
/// The default EventLoop the Lambda is scheduled on.

Sources/AWSLambdaRuntime/LambdaRuntime+ServiceLifecycle.swift

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,14 @@ import ServiceLifecycle
1717

1818
extension LambdaRuntime: Service {
1919
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+
}
2228
}
2329
}
2430
}

Sources/AWSLambdaRuntime/LambdaRuntime.swift

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,13 @@ public final class LambdaRuntime<Handler>: Sendable where Handler: StreamingLamb
5959
#if !ServiceLifecycleSupport
6060
@inlinable
6161
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+
}
6369
}
6470
#endif
6571

Sources/AWSLambdaRuntime/LambdaRuntimeClient.swift

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,9 @@ final actor LambdaRuntimeClient: LambdaRuntimeClientProtocol {
9292
case closed
9393
}
9494

95+
@usableFromInline
96+
var futureConnectionClosed: EventLoopFuture<LambdaRuntimeError>? = nil
97+
9598
private let eventLoop: any EventLoop
9699
private let logger: Logger
97100
private let configuration: Configuration
@@ -372,8 +375,10 @@ final actor LambdaRuntimeClient: LambdaRuntimeClientProtocol {
372375
// however, this happens when performance testing against the MockServer
373376
// shutdown this runtime.
374377
// 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+
)
377382
}
378383
}
379384

@@ -392,6 +397,7 @@ final actor LambdaRuntimeClient: LambdaRuntimeClientProtocol {
392397
return handler
393398
}
394399
} catch {
400+
395401
switch self.connectionState {
396402
case .disconnected, .connected:
397403
fatalError("Unexpected state: \(self.connectionState)")

0 commit comments

Comments
 (0)