swift-timeout icon indicating copy to clipboard operation
swift-timeout copied to clipboard

Add "reset timeout" variants

Open gregcotten opened this issue 9 months ago • 3 comments

Sometimes you just wanna reset the timeout timer if forward progress is made - I think this could be a great feature! Probably just some sort of closure passed to to the caller's async body, something like:

public func withThrowingResettableTimeout<T>(
    isolation: isolated (any Actor)? = #isolation,
    seconds: TimeInterval,
    body: (_ resetTimeout: () -> Void) async throws -> sending T
)

my particular use case would be something like (using FlyingSocks)

try await withThrowingResettableTimeout(seconds: 90) { resetTimeout in
    for try await message in socket.messages {
        resetTimeout()
        let response = try await handleSocketMessage(message.payload)
        try await socket.write(response)
    }
}

try? socket.close()

gregcotten avatar Apr 11 '25 22:04 gregcotten

Could also use @TaskLocal to do something like Task.resetTimeout() instead of passing a closure?

gregcotten avatar Apr 11 '25 23:04 gregcotten

I think this could be quite useful but I don't think a simple () -> Void works well when using the deadline API that requires an instant, a function with labels reads nicely:

try await withThrowingTimeout(after: .now + .seconds(2)) { timeout in
   for await next in sequence {
      timeout.move(after: .now + seconds(2))
   }
}

But that timeout object should be ~Escapable which won't be available until Swift 6.2. Maybe we could make the function that exposes the timeout to be public allowing users to roll their own extension for now?

timeout: @Sendable @escaping () async throws -> Never

swhitty avatar Apr 15 '25 14:04 swhitty

But that timeout object should be ~Escapable which won't be available until Swift 6.2. Maybe we could make the function that exposes the timeout to be public allowing users to roll their own extension for now?

Or just gate ~Escapable with an #if compiler check and warn the library user to not escape the timeout / "will escalate to an error in Swift 6.2"?

gregcotten avatar Apr 15 '25 19:04 gregcotten

I have a sample implementation in https://github.com/swhitty/swift-timeout/pull/4

swhitty avatar Jun 02 '25 06:06 swhitty

@swhitty, yea that looks really good!

gregcotten avatar Jun 02 '25 14:06 gregcotten

I've also added AsyncTimeoutSequence which is a simpler version of what you may need;

Each iteration has its own timeout to return the next element;

for try await val in sequence.timeout(seconds: 2.0) {
   ...
}

swhitty avatar Jun 03 '25 07:06 swhitty