@@ -93,6 +93,14 @@ private struct LambdaHTTPServer {
93
93
case serverReturned( Swift . Result < Void , any Error > )
94
94
}
95
95
96
+ struct UnsafeTransferBox < Value> : @unchecked Sendable {
97
+ let value : Value
98
+
99
+ init ( value: sending Value) {
100
+ self . value = value
101
+ }
102
+ }
103
+
96
104
static func withLocalServer< Result: Sendable > (
97
105
invocationEndpoint: String ? ,
98
106
host: String = " 127.0.0.1 " ,
@@ -135,18 +143,13 @@ private struct LambdaHTTPServer {
135
143
136
144
let server = LambdaHTTPServer ( invocationEndpoint: invocationEndpoint)
137
145
138
- // We are handling each incoming connection in a separate child task. It is important
139
- // to use a discarding task group here which automatically discards finished child tasks.
140
- // A normal task group retains all child tasks and their outputs in memory until they are
141
- // consumed by iterating the group or by exiting the group. Since, we are never consuming
142
- // the results of the group we need the group to automatically discard them; otherwise, this
143
- // would result in a memory leak over time.
146
+ // Sadly the Swift compiler does not understand that the passed in closure will only be
147
+ // invoked once. Because of this we need an unsafe transfer box here. Buuuh!
148
+ let closureBox = UnsafeTransferBox ( value: closure)
144
149
let result = await withTaskGroup ( of: TaskResult< Result> . self , returning: Swift . Result < Result , any Error > . self) { group in
145
-
146
- let c = closure
147
150
group. addTask {
151
+ let c = closureBox. value
148
152
do {
149
-
150
153
let result = try await c ( )
151
154
return . closureResult( . success( result) )
152
155
} catch {
@@ -156,6 +159,12 @@ private struct LambdaHTTPServer {
156
159
157
160
group. addTask {
158
161
do {
162
+ // We are handling each incoming connection in a separate child task. It is important
163
+ // to use a discarding task group here which automatically discards finished child tasks.
164
+ // A normal task group retains all child tasks and their outputs in memory until they are
165
+ // consumed by iterating the group or by exiting the group. Since, we are never consuming
166
+ // the results of the group we need the group to automatically discard them; otherwise, this
167
+ // would result in a memory leak over time.
159
168
try await withThrowingDiscardingTaskGroup { taskGroup in
160
169
try await channel. executeThenClose { inbound in
161
170
for try await connectionChannel in inbound {
0 commit comments