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 {
166166 }
167167 }
168168}
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 {
341341 arguments: processArguments,
342342 workingDirectory: workingDirectory
343343 )
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+ }
345351
346352 indexProcessDidProduceResult (
347353 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