File tree Expand file tree Collapse file tree 3 files changed +63
-1
lines changed Expand file tree Collapse file tree 3 files changed +63
-1
lines changed Original file line number Diff line number Diff line change @@ -166,3 +166,28 @@ extension Collection where Element: Sendable {
166
166
}
167
167
}
168
168
}
169
+
170
+ public struct TimeoutError : Error , CustomStringConvertible {
171
+ public var description : String { " Timed out " }
172
+ }
173
+
174
+ /// Executes `body`. If it doesn't finish after `duration`, throws a `TimeoutError`.
175
+ public func withTimeout< T: Sendable > (
176
+ _ duration: Duration ,
177
+ _ body: @escaping @Sendable ( ) async throws -> T
178
+ ) async throws -> T {
179
+ try await withThrowingTaskGroup ( of: T . self) { taskGroup in
180
+ taskGroup. addTask {
181
+ try await Task . sleep ( for: duration)
182
+ throw TimeoutError ( )
183
+ }
184
+ taskGroup. addTask {
185
+ return try await body ( )
186
+ }
187
+ for try await value in taskGroup {
188
+ taskGroup. cancelAll ( )
189
+ return value
190
+ }
191
+ throw CancellationError ( )
192
+ }
193
+ }
Original file line number Diff line number Diff line change @@ -341,7 +341,13 @@ public struct UpdateIndexStoreTaskDescription: IndexTaskDescription {
341
341
arguments: processArguments,
342
342
workingDirectory: workingDirectory
343
343
)
344
- let result = try await process. waitUntilExitSendingSigIntOnTaskCancellation ( )
344
+ // Time out updating of the index store after 2 minutes. We don't expect any single file compilation to take longer
345
+ // than 2 minutes in practice, so this indicates that the compiler has entered a loop and we probably won't make any
346
+ // progress here. We will try indexing the file again when it is edited or when the project is re-opened.
347
+ // 2 minutes have been chosen arbitrarily.
348
+ let result = try await withTimeout ( . seconds( 120 ) ) {
349
+ try await process. waitUntilExitSendingSigIntOnTaskCancellation ( )
350
+ }
345
351
346
352
indexProcessDidProduceResult (
347
353
IndexProcessResult (
Original file line number Diff line number Diff line change
1
+ //===----------------------------------------------------------------------===//
2
+ //
3
+ // This source file is part of the Swift.org open source project
4
+ //
5
+ // Copyright (c) 2014 - 2018 Apple Inc. and the Swift project authors
6
+ // Licensed under Apache License v2.0 with Runtime Library Exception
7
+ //
8
+ // See https://swift.org/LICENSE.txt for license information
9
+ // See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10
+ //
11
+ //===----------------------------------------------------------------------===//
12
+
13
+ import LSPTestSupport
14
+ import SKSupport
15
+ import XCTest
16
+
17
+ final class AsyncUtilsTests : XCTestCase {
18
+ func testWithTimeout( ) async throws {
19
+ let expectation = self . expectation ( description: " withTimeout body finished " )
20
+ await assertThrowsError (
21
+ try await withTimeout ( . seconds( 0.1 ) ) {
22
+ try ? await Task . sleep ( for: . seconds( 10 ) )
23
+ XCTAssert ( Task . isCancelled)
24
+ expectation. fulfill ( )
25
+ }
26
+ ) { error in
27
+ XCTAssert ( error is TimeoutError , " Received unexpected error \( error) " )
28
+ }
29
+ try await fulfillmentOfOrThrow ( [ expectation] )
30
+ }
31
+ }
You can’t perform that action at this time.
0 commit comments