@@ -75,6 +75,53 @@ struct LambdaRuntimeTests {
7575 taskGroup. cancelAll ( )
7676 }
7777 }
78+ @Test ( " run() must be cancellable " )
79+ func testLambdaRuntimeCancellable( ) async throws {
80+
81+ let logger = Logger ( label: " LambdaRuntimeTests.RuntimeCancellable " )
82+ // create a runtime
83+ let runtime = LambdaRuntime (
84+ handler: MockHandler ( ) ,
85+ eventLoop: Lambda . defaultEventLoop,
86+ logger: logger
87+ )
88+
89+ // Running the runtime with structured concurrency
90+ // Task group returns when all tasks are completed.
91+ // Even cancelled tasks must cooperatlivly complete
92+ await #expect( throws: Never . self) {
93+ try await withThrowingTaskGroup ( of: Void . self) { taskGroup in
94+ taskGroup. addTask {
95+ logger. trace ( " --- launching runtime ---- " )
96+ try await runtime. run ( )
97+ }
98+
99+ // Add a timeout task to the group
100+ taskGroup. addTask {
101+ logger. trace ( " --- launching timeout task ---- " )
102+ try await Task . sleep ( for: . seconds( 5 ) )
103+ if Task . isCancelled { return }
104+ logger. trace ( " --- throwing timeout error ---- " )
105+ throw TestError . timeout // Fail the test if the timeout triggers
106+ }
107+
108+ do {
109+ // Wait for the runtime to start
110+ logger. trace ( " --- waiting for runtime to start ---- " )
111+ try await Task . sleep ( for: . seconds( 1 ) )
112+
113+ // Cancel all tasks, this should not throw an error
114+ // and should allow the runtime to complete gracefully
115+ logger. trace ( " --- cancel all tasks ---- " )
116+ taskGroup. cancelAll ( ) // Cancel all tasks
117+ } catch {
118+ logger. error ( " --- catch an error: \( error) " )
119+ throw error // Propagate the error to fail the test
120+ }
121+ }
122+ }
123+
124+ }
78125}
79126
80127struct MockHandler : StreamingLambdaHandler {
@@ -86,3 +133,15 @@ struct MockHandler: StreamingLambdaHandler {
86133
87134 }
88135}
136+
137+ // Define a custom error for timeout
138+ enum TestError : Error , CustomStringConvertible {
139+ case timeout
140+
141+ var description : String {
142+ switch self {
143+ case . timeout:
144+ return " Test timed out waiting for the task to complete. "
145+ }
146+ }
147+ }
0 commit comments