-
Notifications
You must be signed in to change notification settings - Fork 534
Prepare for 0.4.0.M1 #61
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 8 commits
8b4d958
af380eb
092302b
5bab96e
0d11049
cf09f74
98a06e5
1ae8ba0
ec7c3bd
b0671e5
e6999a4
0561b6c
c800041
29804c5
e500c91
bc2576c
0a90836
f18f8f1
1883f39
5b02393
6dcb7ff
eed3826
8ffc64d
5aba6f8
f709200
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,3 +21,4 @@ github name | Real Name, Email Address used for git commits, Company | |
rkuhn | Roland Kuhn, [email protected], Typesafe Inc. | ||
benjchristensen| Ben Christensen, [email protected], Netflix Inc. | ||
viktorklang | Viktor Klang, [email protected], Typesafe Inc. | ||
smaldini | Stephane Maldini, [email protected], Pivotal Software Inc. |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,13 +6,13 @@ The latest preview release is available on Maven Central as | |
|
||
<dependency> | ||
<groupId>org.reactivestreams</groupId> | ||
<artifactId>reactive-streams-spi</artifactId> | ||
<version>0.3</version> | ||
<artifactId>reactive-streams</artifactId> | ||
<version>0.4.0.M1</version> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.reactivestreams</groupId> | ||
<artifactId>reactive-streams-tck</artifactId> | ||
<version>0.3</version> | ||
<version>0.4.0.M1</version> | ||
</dependency> | ||
|
||
## Goals, Design and Scope ## | ||
|
@@ -47,6 +47,7 @@ The API consists of the following components that are required to be provided by | |
- Publisher | ||
- Subscriber | ||
- Subscription | ||
- Processor | ||
|
||
A *Publisher* is a provider of a potentially unbounded number of sequenced elements, publishing them according to the demand received from its Subscriber(s). | ||
|
||
|
@@ -73,6 +74,16 @@ public interface Subscriber<T> { | |
- A `Subscriber` MUST NOT block a `Publisher` thread. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should have a footnote to define what |
||
- A `Subscriber` MUST signal demand via `Subscription.request` to receive notifications. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is not true—onError and onComplete can happen without demand. |
||
- A `Subscriber` MAY behave synchronously or asynchronously but SHOULD NOT synchronously perform heavy computations in its methods (`onNext`, `onError`, `onComplete`, `onSubscribe`). | ||
- A `Subscriber.onNext(T t)` and `Subscriber.onSubscribe(Subscription s)` MUST NOT call any methods on the `Subscription`, the `Publisher` or any other `Publishers` or `Subscribers`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am not sure about that @viktorklang @benjchristensen @jbrisbin There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. If the Subscriber is allowed synchronous, then this would be a weird rule (to me). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. +1 |
||
- A `Subscriber.onComplete()` and `Subscriber.onError(Throwable t)` MUST NOT call any methods on the `Subscription`, the `Publisher` or any other `Publishers` or `Subscribers`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This either. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Well, at least in the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. See the next line: |
||
- A `Subscriber.onComplete()` and `Subscriber.onError(Throwable t)` MUST consider the Subscription cancelled after having received the event | ||
- A `Subscriber` MUST NOT accept an `onSubscribe` event if it already has an active Subscription. What exactly "not accepting" means is left to the implementation but should include behavior that makes the user aware of the usage error (e.g. by logging, throwing an exception or similar). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we "refactor" this part: "What exactly "not accepting" means is left to the implementation but should include behavior that makes the user aware of the usage error (e.g. by logging, throwing an exception or similar)." into a general recommendation as to what should be done for spec violations? |
||
- A `Subscriber` MUST call `Subscription.cancel()` during shutdown if it still has an active `Subscription`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Clarify this to mean "A |
||
- A `Subscriber` MUST ensure that all calls on a `Subscription` take place from the same thread or provide for respective external synchronization. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Replace "a |
||
- A `Subscriber` MUST be prepared to receive one or more `onNext` events after having called `Subscription.cancel()` if there are still requested elements pending. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Add footnote explaining why this is needed? |
||
- A `Subscriber` MUST be prepared to receive an `onComplete` event with or without a preceding `Subscription.request(int n)` call. | ||
- A `Subscriber` MUST be prepared to receive an `onError` event with or without a preceding `Subscription.request(int n)` call. | ||
- A `Subscriber` MUST make sure that all calls on its `onXXX` methods happen-before the processing of the respective events. I.e. the Subscriber must take care of properly publishing the event to its processing logic. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this still relevant with the latest discussions about Subscriber @reactive-streams/contributors There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I believe this is still valid. If one uses an AsyncSubscriber the invocation of onX must happen-before the processing of that signal. |
||
|
||
|
||
#### Publisher ([Code](https://github.com/reactive-streams/reactive-streams/blob/master/api/src/main/java/org/reactivestreams/Publisher.java)) | ||
|
@@ -90,14 +101,19 @@ public interface Publisher<T> { | |
- If a `Publisher` terminates successfully (finite stream) it MUST emit an `onComplete`. | ||
- If a Publisher signals either `onError` or `onComplete` on a `Subscriber`, that `Subscriber`’s `Subscription` MUST be considered canceled. | ||
- Once a terminal state has been signaled (`onError`, `onComplete`) it is REQUIRED that no further events can be sent. | ||
- Upon receiving a `Subscription.cancel` request it SHOULD stop sending events as soon as it can. | ||
- Upon receiving a `Subscription.cancel` request it SHOULD stop sending events as soon as it can. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'd want to rephrase this (since the SHOULD is ambiguous about whether it is allowed to continue sending events indefinitely, or whether it is allowed to be slow in stopping): Upon receiving a |
||
- `Subscription`'s which have been canceled SHOULD NOT receive subsequent `onError` or `onComplete` events, but implementations will not be able to strictly guarantee this in all cases due to the intrinsic race condition between actions taken concurrently by `Publisher` and `Subscriber`. | ||
- A `Publisher` SHOULD NOT throw an `Exception`. The only legal way to signal failure (or reject a `Subscription`) is via the `Subscriber.onError` method. | ||
- The `Subscriber.onSubscribe` method on a given `Subscriber` instance MUST NOT be called more than once. | ||
- The `Publisher.subscribe` method MAY be called as many times as wanted but MUST be with a different `Subscriber` each time. | ||
- The `Publisher.subscribe` method MAY be called as many times as wanted but MUST be with a different `Subscriber` each time, based on object equality. It MUST reject the Subscription with a `java.lang.IllegalStateException` if the same Subscriber already has an active `Subscription` with this `Publisher`. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This sounds nicer to me: "The |
||
- A `Publisher` MAY support multi-subscribe and choose whether each `Subscription` is unicast or multicast. | ||
- A `Publisher` MAY reject calls to its `subscribe` method if it is unable or unwilling to serve them (e.g. because it is overwhelmed or bounded by a finite number of underlying resources, etc...). If rejecting it MUST do this by calling `onError` on the `Subscriber` passed to `Publisher.subscribe` instead of calling `onSubscribe`". | ||
|
||
- A `Publisher` in `completed` state MUST NOT call `Subscriber.onSubscribe` and MUST emit an `Subscriber.onComplete` on the given `Subscriber` | ||
- A `Publisher` in `error` state MUST NOT call `Subscriber.onSubscribe` and MUST emit an `Subscriber.onError` with the error cause on the given `Subscriber` | ||
- A `Publisher` in `shut-down` state MUST NOT call `Subscriber.onSubscribe` and MUST emit an `Subscriber.onError` with `java.lang.IllegalStateException` on the given `Subscriber` | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For all these spec violation There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Even better if it also quoted the spec |
||
- A `Publisher` MUST support a pending element count up to 2^63-1 (java.lang.Long.MAX_VALUE) and provide for overflow protection. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should be made explicit what overflow protection in this case entails. |
||
- A `Publisher` MUST produce the same elements in the same sequence for all its subscribers. Producing the stream elements at (temporarily) differing rates to different subscribers is allowed. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Check if still relevant @reactive-streams/contributors |
||
- A `Publisher` MUST start producing with the oldest element still available for a new subscriber. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Check if still relevant @reactive-streams/contributors There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think this is still relevant. |
||
|
||
|
||
#### Subscription ([Code](https://github.com/reactive-streams/reactive-streams/blob/master/api/src/main/java/org/reactivestreams/Subscription.java)) | ||
|
@@ -114,9 +130,28 @@ public interface Subscription { | |
- The `Subscription.request` method MUST assume that it will be invoked synchronously and MUST NOT allow unbounded recursion such as `Subscriber.onNext` -> `Subscription.request` -> `Subscriber.onNext`. | ||
- The `Subscription.request` method SHOULD NOT synchronously perform heavy computations. | ||
- The `Subscription.cancel` method MUST assume that it will be invoked synchronously and SHOULD NOT synchronously perform heavy computations. | ||
- When the `Subscription` is cancelled, `Subscription.request(int n)` MUST ignore the call. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "When the "After the |
||
- When the `Subscription` is cancelled, `Subscription.cancel()` MUST ignore the call. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. "After the Subscription is cancelled, additional Subscription.cancel() MUST be NOPs." <- I find this less confusing then "ignore the call" |
||
- When the `Subscription` is not cancelled, `Subscription.request(int n)` MUST register the given number of additional elements to be produced to the respective subscriber. | ||
- When the `Subscription` is not cancelled, `Subscription.request(int n)` MUST throw a `java.lang.IllegalArgumentException` if the argument is <= 0. | ||
- When the `Subscription` is not cancelled, `Subscription.request(int n)` COULD synchronously call `onNext` on this (or other) subscriber(s) if and only if the next element is already available. | ||
- When the `Subscription` is not cancelled, `Subscription.request(int n)` COULD synchronously call `onComplete` or `onError` on this (or other) subscriber(s). | ||
- When the `Subscription` is not cancelled, `Subscription.cancel()` the `Publisher` MUST eventually cease to call any methods on the corresponding subscriber. | ||
- When the `Subscription` is not cancelled, `Subscription.cancel()` the `Publisher` MUST eventually drop any references to the corresponding subscriber. Re-subscribing with the same `Subscriber` instance is discouraged, but this specification does not mandate that it is disallowed since that would mean having to store previously canceled subscriptions indefinitely. | ||
- When the `Subscription` is not cancelled, `Subscription.cancel()` the `Publisher` MUST shut itself down if the given Subscription is the last downstream `Subscription`. Explicitly adding "keep-alive" Subscribers SHOULD prevent automatic shutdown if required. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Weird wording around " |
||
|
||
#### Processor ([Code](https://github.com/reactive-streams/reactive-streams/blob/master/api/src/main/java/org/reactivestreams/Processor.java)) | ||
|
||
```java | ||
public interface Processor<T, R> extends Subscriber<T>, Publisher<R> { | ||
} | ||
```` | ||
|
||
|
||
- A `Processor` represents a processing stage—which is both a `Subscriber` and a `Publisher` and obeys the contracts of both. | ||
- A `Processor` must cancel its upstream Subscription if its last downstream Subscription has been cancelled | ||
- A `Processor` must immediately pass on `onError` events received from its upstream to its downstream | ||
- A `Processor` must be prepared to receive incoming elements from its upstream even if a downstream subscriber has not | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand this rule There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Not that much too, it is from the previous TCK tho. My understanding is simply that the initial capacity on a Processor might be positive (the spec assumes the opposite). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ah, it is to express that it may behave like an active Subscriber before it behaves like an active Publisher |
||
requested anything yet | ||
|
||
### Asynchronous vs Synchronous Processing ### | ||
|
||
|
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I propose that we give identifiers to ALL spec rules so it is easy to refer to them from other rules.