Skip to content
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

Update specification with supporting of unbounded mode for request(n) #325

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

olme04
Copy link

@olme04 olme04 commented Mar 29, 2022

Update specification with supporting of unbounded mode for request(n) to overcome absence of Magic Number from Reactive Streams specification

Motivation:

In Reactive Streams specification, and in Project Reactor (implementation of spec), there is possibility to make stream unbounded by using magic number (2^63-1 (java.lang.Long.MAX_VALUE)) when calling request(n) on subscription.
But in RSocket there is no this magic number, as it uses 4 bytes instead of 8.
So rsocket-java, emulates unbounded mode by sending Int.MAX_VALUE instead or magic number if it appears.
And also current implementation can go into an unbounded mode when during stream lifetime, SUM of all request(n) for stream is more than Int.MAX_VALUE. After stream becomes unbounded, there will be no more REQUEST_N frames sent there.

The problem is, that, if implementation don't do the same thing (because this behavior isn't specified in specification), those Int.MAX_VALUE credits can be exhausted in relatively small period of time in real use case: 12-15 hours, as found by @marcelja.

Modifications:

Adding U bit to REQUEST_N, REQUEST_STREAM and REQUEST_CHANNEL frames to enable unbounded mode and make it possible to better interop with Reactive Streams specification.

Result:

Implementation SHOULD handle such bit, and make it possible to request unbounded stream.
F.e. in rsocket-java there should be mapping when using request(n) where n is of Long type (so magic number is available) to use unbounded mode if Long.MAX_VALUE appears.

… to overcome absence of Magic Number from Reactive Streams specification
@viglucci
Copy link
Member

viglucci commented Apr 28, 2022

Have we explored alternatively adding a new Flag to appropriate frames to denote Unbounded Demand, rather than repurposing the proposed bit? I would be concerned that as proposed, repurposing the bit could be troublesome for implementations that are currently working with the existing understanding, and could potentially introduce interop issues for implementations lagging behind the spec.

Adding a new Flag feels more "additive" and non-breaking than repurposing this bit as currently proposed.

REQUEST_STREAM Frame (0x06)

Frame Contents

     0                   1                   2                   3
     0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
    +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
    |                           Stream ID                           |
    +-----------+-+-+-+-------------+-------------------------------+
    |Frame Type |0|M|F|U|    Flags    |
    +-------------------------------+-------------------------------+
    |0|                    Initial Request N                        |
    +---------------------------------------------------------------+
                          Metadata & Request Data

^-- U flag to denote unbounded demand. Initial Request N and all REQUEST_N frames can be ignored.

@yuriykulikov
Copy link

It seems that adding an U flag will be a breaking change, because when an U-flag-enabled client communicates with an outdated server, the server will be unaware of the unbounded mode and won't send any messages. Using the U-bit, however, will be considered as a large credit by the server and communication will continue to work until the credit is exhausted.

@viglucci
Copy link
Member

viglucci commented Apr 28, 2022

the server will be unaware of the unbounded mode and won't send any messages

After giving it some more thought, I think that this would be preferable behavior over the stream terminating at some arbitrary point in the future due to exhausting the demand that the requester intended to be unbounded. I would argue that a failure that happens at integration time due to a protocol mismatch is preferable to one that happens many hours in the future, and only when a sufficient amount of time has passed.

I would also suggest that it's important for the protocol and implementations to be deliberate and rigid (where appropriate), rather than permissive to protocol mismatches in this case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants