Commit Graph

12 Commits

Author SHA1 Message Date
David Nadoba e0cc6dd6ff
Throw `CancellationError` instead of returning `nil` during early cancellation. (#2401)
### Motivation:
Follow up PR for https://github.com/apple/swift-nio/pull/2399

We currently still return `nil` if the current `Task` is canceled before the first call to `NIOThrowingAsyncSequenceProducer.AsyncIterator.next()` but it should throw `CancellationError` too.

In addition, the generic `Failure` type turns out to be a problem. Just throwing a `CancellationError` without checking that `Failure` type is `any Swift.Error` or `CancellationError` introduced a type safety violation as we throw an unrelated type.

### Modifications:

- throw `CancellationError` on eager cancellation
-  deprecates the generic `Failure` type of `NIOThrowingAsyncSequenceProducer`. It now must always be `any Swift.Error`. For backward compatibility we will still return nil if `Failure` is not `any Swift.Error` or `CancellationError`.

### Result:

`CancellationError` is now correctly thrown instead of returning `nil` on eager cancelation. Generic `Failure` type is deprecated.
2023-04-11 08:58:01 -07:00
David Nadoba 75cea45e61
Throw `CancellationError` if `NIOThrowingAsyncSequenceProducer.AsyncIterator.next()` is cancelled instead of returning `nil` (#2399)
* Throw `CancellationError` if `NIOThrowingAsyncSequenceProducer.AsyncIterator.next()` is cancelled instead of returning `nil`

* Update doc comment

* Fix typo
2023-04-05 17:37:43 +01:00
Franz Busch ef7dc666e8
Rework the `NIOAsyncSequenceProducer` tests to rely less on timings (#2386) 2023-03-07 17:28:34 +00:00
carolinacass 5db1dfabb0
Building swift-nio with Swift 5.7 for iOS using Xcode 14.0 at 2.48.0. (#2369)
Motivation:
swift- nio was failing builds that should pass

Modifications:
Adding available to the necessary sections
2023-02-17 10:05:43 -08:00
Franz Busch 45167b8006
Fix flaky testTaskCancel_whenStreaming_andNotSuspended (#2355)
# Motivation
Currently `testTaskCancel_whenStreaming_andNotSuspended` is flaky since `didTerminate` can be called after the iterator is dropped. Fixes https://github.com/apple/swift-nio/issues/2354

# Modification
Let's modify that slightly so we hight the condition we want to hit.

# Result
No more flaky tests.
2023-01-25 14:09:22 +00:00
Franz Busch 0243bb4c8e
Fix `testTaskCancel_whenStreaming_andNotSuspended` flakiness (#2314)
# Motivation
This test has been flaky for some time. This was due to the fact that the consuming Task could have deinited the iterator which has resulted in a call to `didTerminate`.

# Modification
This PR, adds a small sleep in the consuming task to avoid this race.

# Result
No more flakiness in this test.

Co-authored-by: David Nadoba <d_nadoba@apple.com>
2022-11-14 03:20:09 -08:00
David Nadoba c7b4989b02
Remove `#if compiler(>=5.5)` (#2292)
### Motivation
We only support Swift 5.5.2+.

### Modification
Remove all `#if swift(>=5.5)` conditional compilation blocks.

### Result
less branching
2022-10-13 07:17:46 -07:00
Franz Busch f144292e5d
Implement a `NIOAsyncWriter` (#2251)
* Implement a `NIOAsyncWriter`

# Motivation
We previously added the `NIOAsyncProducer` to bridge between the NIO channel pipeline and the asynchronous world. However, we still need something to bridge writes from the asynchronous world back to the NIO channel pipeline.

# Modification
This PR adds a new `NIOAsyncWriter` type that allows us to asynchronously `yield` elements to it. On the other side, we can register a `NIOAsyncWriterDelegate` which will get informed about any written elements. Furthermore, the synchronous side can toggle the writability of the `AsyncWriter` which allows it to implement flow control.
A main goal of this type is to be as performant as possible. To achieve this I did the following things:
- Make everything generic and inlinable
- Use a class with a lock instead of an actor
- Provide methods to yield a sequence of things which allows users to reduce the amount of times the lock gets acquired.

# Result
We now have the means to bridge writes from the asynchronous world to the synchronous

* Remove the completion struct and incorporate code review comments

* Fixup some refactoring leftovers

* More code review comments

* Move to holding the lock around the delegate and moved the delegate into the state machine

* Comment fixups

* More doc fixes

* Call finish when the sink deinits

* Refactor the writer to only yield Deques and rename the delegate to NIOAsyncWriterSinkDelegate

* Review

* Fix some warnings

* Fix benchmark sendability

* Remove Failure generic parameter and allow sending of an error through the Sink
2022-09-21 02:53:53 -07:00
Franz Busch 6431296d6b
Call finish once the Source is deinited (#2258)
* Call finish once the Source is deinited

# Motivation
We **MUST** call `finish()` when the `Source` deinits otherwise we can have a suspended continuation that never gets resumed.

# Modification
Introduce an internal class to both `Source`s and call `finish()` in their `deinit`s.

# Result
We are now resuming all continuations.

* Remove @unchecked
2022-09-02 10:01:11 +01:00
Franz Busch 2c453d6e49
Small changes for the `NIOAsyncSequenceProducer` (#2254)
* Small changes for the `NIOAsyncSequenceProducer`

# Motivation
In the PR for the `NIOAsyncWriter`, a couple of comments around naming of `private` properties that needed to be `internal` due to inlinability and other smaller nits came up.

# Modification
This PR includes two things:
1. Fixing up of the small nits like using `_` or getting the imports inside the `#if` checks
2. Changing the public API of the `makeSequence` to be aligned across the throwing and non-throwing one.

# Result
Cleaner code and alinged APIs.

* Fix refactoring left-overs
2022-08-30 16:53:00 +01:00
Franz Busch ff19f496bd
Add throwing version of `NIOAsyncSequenceProducer` (#2237)
* Add throwing version of `NIOAsyncSequenceProducer`

# Motivation
We recently introduced a `NIOAsyncSequenceProducer` to bridge a stream of elements from the NIO world into the async world. The introduced type was a non-throwing `AsyncSequence`. To support all use-cases we also need to offer a throwing variant of the type.

# Modification
- Introduce a new `NIOThrowingAsyncSequenceProducer` that is identical to the `NIOAsyncSequenceProducer` except that it has a `Failure` generic parameter and that the `next()` method is throwing.
- Extract the `StateMachine` from both `AsyncSequenceProducer`s and unify them.
- There is one modification in behaviour: `didTerminate` is now only called after `nil` or the error has been consumed from the sequence.

# Result
We now have a throwing variant of the `NIOAsyncSequenceProducer`.

* Code review and fix CI

* Remove duplicated code

Co-authored-by: Cory Benfield <lukasa@apple.com>
2022-08-09 23:34:17 -07:00
Franz Busch dd40215fd4
Implement a back-pressure aware `AsyncSequence` source (#2230)
* Implement a back-pressure aware `AsyncSequence` source

# Motivation
We ran into multiple use-cases (https://github.com/apple/swift-nio/pull/2067, https://github.com/grpc/grpc-swift/blob/main/Sources/GRPC/AsyncAwaitSupport/PassthroughMessageSource.swift) already where we want to vend an `AsyncSequence` where elements are produced from the sync world while the consumer is in the async world. Furthermore, we need the `AsyncSequence` to properly support back-pressure.
Since we already identified that this is something fundamental for our ecosystem and that current `AsyncSequence` sources are not providing the proper semantics or performance, it would be great to find a single solution that we can use everywhere.

Before diving into the code, I think it is good to understand the goals of this `AsyncSequence`:
- The `AsyncSequence` should support a single unicast `Subscriber`
- The `AsyncSequence` should allow a pluggable back-pressure strategy
- The `AsyncSequence` should allow to yield a sequence of elements to avoid aquiring the lock for every element.
- We should make sure to do as few thread hops as possible to signal the producer to demand more elements.

# Modification
This PR introduces a new `AsyncSequence` called `NIOBackPressuredAsyncSequence`. The goal of that sequence to enable sync to async element streaming with back-pressure support.

# Result
We can now power our sync to async use-cases with this new `AsyncSequence`.

# Future work
There are couple of things left that I wanna land in a follow up PR:
1. An adaptive back-pressure strategy that grows and shrinks depending on the speed of consumption
2. A throwing version of this sequence
3. Potentially an async version that suspends on `yield()` and resumes when more elements should be demanded.

* Fix cancellation handling

* Review

* Add init helper

* Add return types to help the type checker

* Fix 5.7 CI

* Rename delegate method and update docs

* Review

* Switch to Deque, rename the type and change the behaviour of yielding an empty sequence

* Review comments from George

* Review comments by Konrad

* Review and add tests for the high low strategy

* Fix 5.4 tests

* Code review

Co-authored-by: Cory Benfield <lukasa@apple.com>
2022-08-04 15:58:28 +01:00