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
Ambiguity with COMPLETE
flag in Response
frame
#126
Comments
I had a discussion about this from the Reactive Streams API perspective. Unless the implementation does batching, there isn't a means to signal an |
Why would there be an empty payload? In request-response, I agree that either "onNext+onComplete" or "onError" is required. A request_response should always receive a NEXT_COMPLETE. It should be an error to even send a response frame without a payload on request_response. Do we need to add something to the spec that clarifies or enforces this? |
@benjchristensen I think empty content is a valid usecase, eg: HTTP 204 is a valid status code which does not have any content. One option could be that we also check for metadata length but that could also be empty especially if it is over H2 which does header compression. @tmontgomery Yes that is my belief too. Even if we do batching, there may be a function downstream that adds something to the batch. eg: |
But this isn't HTTP, and onComplete doesn't carry messages, so something like an "HTTP 204" either would have to be delivered in an onNext payload, or as an onError message. So no, I don't think it's valid, just because HTTP does it. ReactiveSocket isn't HTTP. |
So are you suggesting that when the payload is empty, we have two options:
(Currently, we send a If yes, then which one do you prefer? |
There should not be an empty request-response that just completes. That breaks the ReactiveStreams spec which does not allow nulls. So if someone tries to return a null (an empty response), then it has to be onError. |
I think empty byte buffer and null are two different cases. |
Then send an empty byte buffer, as long as your mimetype knows what to do with it. |
The point is that request/response expects a non-null response to represent success. The ReactiveSocket state machine will always process the payload and emit onNext for request/response. |
Sounds like we should nail this down in the spec ... basically for each of the interaction models, what the expected contract is.
|
I think an empty (!= null) response is perfectly valid, thus we need to distinguish between an empty I agree that we should specify all of that in the spec. |
How would "empty" work with something like the Are you saying an empty response would only call onComplete and not invoke onNext? |
In the case of request/response implemented with It is more pathologic in the case of request/stream, where an empty response will be interpreted as an |
So I don't see how "there's no difference" with |
@NiteshKant are going for a |
@abersnaze the current state is that request-response acts like a |
Reading through the exchange, it looks like sending an empty Is this side-effect acceptable? |
Why are empty responses being sent? That's not what request/response is in ReactiveSocket. As far as ReactiveSocket is concerned, a response payload has to be sent, or it's an error. The application can choose to interpret a payload as "empty" based on mime-type, but why are we trying to make request/response not have a response? |
Ok, so the definition of empty response is perhaps not defined here. When I say:
I refer to empty as |
I think the confusion is coming from the definition of "empty response". Returning |
@NiteshKant yes, an "empty" stream means no 'onNext', as per @stevegury in the example you're giving, I agree with you, it should receive both 'onNext' and 'onComplete'. If by "empty" it just means an empty string or byte array, then that's semantic to the application, but it is still a payload being sent via 'onNext', which is what is expected on a request/response. |
Agreed. I created this issue to move away from this current behavior.
Yes. The PR for the java implementation I linked to does this change to always treat a Purpose of this issueThe above approach works BUT it has a side effect (as I mentioned here) that all The intent here is to see whether there is an opportunity to improve this state. Few options come to my mind:
|
Ideally, I would prefer to add a new flag indicating that it's a |
How is having an extra flag any more clear that just looking at the data section being > 0 bytes? Response frame: https://github.com/ReactiveSocket/reactivesocket/blob/master/Protocol.md#response-frame
If C=1, and data == 0 bytes, then it is onComplete. Thus, pseudocode that ignores the 4th erroneous case would basically look like this:
Handling that 4th case, probably something like this:
Considering this logic, which can all be done just by looking at the frame, I don't see a need for the extra flag. Is there an efficiency gain or some other behavior that can be achieved with the additional flag that can't be done by the reader using the above logic? |
By the way, I ran into this tonight and have this line in my code right now: // temporary fix until https://github.com/ReactiveSocket/reactivesocket/issues/126 is resolved
.filter(p -> p.getData().remaining() > 0) |
Doesn't work for request-response as there won't be any |
@benjchristensen great minds... rsocket/rsocket-java#214 |
That would be an error in that case. The client library implementation still needs to maintain the contract of whatever interaction model it's within. So on request/response, C==1, data == 0 bytes is invalid and should cause onError. Changing the specification with flags doesn't prevent the implementation needing to validate correct behavior. |
I think this is the main disagreement between us. @stevegury seems to agree that data == 0 bytes is valid. What do others think? |
I don't like the data == 0 bytes being a special value. REQUEST_RESPONSE should be able to complete with a single empty payload. REQUEST_STREAM should be able to contain empty payloads mid stream, at the end of stream and generally the sequence of payloads that a server implementor sends should be seen by the client in all cases by default. Just works I think I disagree with the statement by @benjchristensen, "If C=0, and data == 0 bytes, then it is a bad frame and should call onError or kill the entire connection." In a stream, why isn't an empty payload acceptable. As a pure user of the reactivesocket protocol, why can't my stream of responses be time based e.g. every minute here is the data I received, possibly empty? |
Is 0 bytes a null? If so, that breaks the ReactiveStreams contract which doesn't support nulls. If it's a semantically empty payload, such as a CBOR object that has no data, then that would not be 0 bytes. It would have some bytes to represent the CBOR object which then has no key/values in it. |
|
If the type being communicate is |
As per discussion in #126 in order to remove ambiguity and use of sentinel value of 0-bytes, and allow 0-byte payloads.
I have submitted a proposal to add the Next flag: https://github.com/ReactiveSocket/reactivesocket/pull/137/files |
Thanks, BTW this is a perfectly valid HTTP Response also. So happy we haven't special cased this out. content-length: 0 |
* Add RESPONSE Next Flag As per discussion in #126 in order to remove ambiguity and use of sentinel value of 0-bytes, and allow 0-byte payloads. * Update Protocol.md * Clarify Data or Metadata for Next. * Clarify the sample code
This was done in #137 |
Background
Response Frame is designed to eliminate the need of exchanging an additional frame for
COMPLETE
in cases where it is known while emitting anonNext
that there are no more items.This optimization is pretty useful for
Request-Response
exchange when it is known beforehand that there would only be one response frame (post fragmented frame coalescing).In practice, this is less useful for request-stream, request-channel interactions where the presence of a functional composition library makes it more complex to determine whether an item is the last in the stream.
Problem
Since there is no explicit indication that a
RESPONSE
frame isNEXT_COMPLETE
or justCOMPLETE
, a way to determine whether one should emit an item before completing is to check whether thisRESPONSE
contains any data or not. Java Implementation uses this approach.As shown in this PR, this approach is error-prone for request-response interaction as an empty payload converts to just emit
onComplete()
. I will consider this as an error as request-response should expect either a response or an error.The text was updated successfully, but these errors were encountered: