Skip to content

Fixes behavior of RequestChannel - #736

Merged
OlegDokuka merged 5 commits into
developfrom
bugfix/request_channel
Apr 9, 2020
Merged

Fixes behavior of RequestChannel #736
OlegDokuka merged 5 commits into
developfrom
bugfix/request_channel

Conversation

@OlegDokuka

@OlegDokukaOlegDokuka commented Jan 24, 2020

Copy link
Copy Markdown
Member

This PR provides a fix for the incorrect behavior of RequestChannel.

At this moment there is a couple of issues with that:

1.1) There was an incorrect expectation of signal ordering which is requestN from the local downstream, onNext from the local upstream. In fact, signal order can be totally different and while we wait for first onNext signal, nothing prevents to perform a few more requestN which is going to break correctness (see https://github.com/rsocket/rsocket-java/pull/736/files#diff-a87c12662c200847a65e4b44b57e2278R236)

1.2) There was an incorrect behavior in case upstream terminates earlier than the remote responder so the downstream observed onComplete before it should do so. The RSocket-Spec says that the stream can be half-closed until both sides send the complete signal. (https://github.com/rsocket/rsocket-java/pull/736/files#diff-b0fea90eb4e3536e65de608e97f637f9L369)

  1. I found that there could be racing between sending first frame and cancelation, so I added an additional flag that ensures that we released the given frame and no leaks going to appear. (see https://github.com/rsocket/rsocket-java/pull/736/files#diff-b0fea90eb4e3536e65de608e97f637f9R394)

  2. In order to implement correct behavior of request channel I reimplemented the switchOnFirst operator to follow the behavior defined by RSocket-Spec (https://github.com/rsocket/rsocket-java/pull/736/files#diff-ec51e7f167b7b31f5b3c4b25f5233e8dR1)

  3. This PR is a temporary fix on the upcoming rewriting of every stream to state-machine it is done in the RSocket-CPP https://github.com/rsocket/rsocket-cpp/tree/master/rsocket/statemachine

Signed-off-by: Oleh Dokuka shadowgun@i.ua

@yschimke

Copy link
Copy Markdown
Member

Did you miss a file? or is this a draft?

@OlegDokuka

Copy link
Copy Markdown
MemberAuthor

@yschimke pushed fix

@OlegDokuka
OlegDokukaforce-pushed the bugfix/request_channel branch 4 times, most recently from e24f3c2 to ff009c8CompareJanuary 27, 2020 12:17

@simonbaslesimonbasle left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is way too much for me to digest on a single commit, but I still have small general remarks. I didn't review the logic rework itself in any depth

Comment threadrsocket-core/src/main/java/io/rsocket/RSocketRequester.java Outdated
Comment threadrsocket-core/src/main/java/io/rsocket/RSocketResponder.java Outdated
Comment threadrsocket-core/src/main/java/io/rsocket/internal/FluxSwitchOnFirst.java Outdated
@OlegDokukaOlegDokuka mentioned this pull request Feb 7, 2020
@rstoyanchevrstoyanchev mentioned this pull request Mar 2, 2020
@OlegDokuka

Copy link
Copy Markdown
MemberAuthor

suppressed by #761

@OlegDokukaOlegDokuka reopened this Apr 3, 2020
@OlegDokuka
OlegDokukaforce-pushed the bugfix/request_channel branch 2 times, most recently from d321e68 to c853a39CompareApril 3, 2020 20:08
@OlegDokukaOlegDokuka linked an issue Apr 5, 2020 that may be closed by this pull request
@OlegDokukaOlegDokuka added this to the 1.0 milestone Apr 5, 2020
@OlegDokukaOlegDokuka self-assigned this Apr 5, 2020
@OlegDokuka
OlegDokukaforce-pushed the bugfix/request_channel branch 4 times, most recently from 5339a88 to 268e1aeCompareApril 5, 2020 14:02
Signed-off-by: Oleh Dokuka <shadowgun@i.ua>
Signed-off-by: Oleh Dokuka <shadowgun@i.ua>
Signed-off-by: Oleh Dokuka <shadowgun@i.ua>
@OlegDokuka
OlegDokukaforce-pushed the bugfix/request_channel branch from 268e1ae to ab0ce37CompareApril 9, 2020 11:52
Signed-off-by: Oleh Dokuka <shadowgun@i.ua>
.verify(getTimeout());

Assertions.assertThat(requested.get())
.isEqualTo(257L); // 257 because of eager behavior of limitRate

@OlegDokukaOlegDokukaApr 9, 2020

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@rstoyanchev for your attention. Here is the result of eager prefetch 1L (from the switchOnFirst + 256 extra from limitRate)

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

oh... found a bug because of skip does extra request 1 but it should not

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed. prefetch should be exactly 256

Signed-off-by: Oleh Dokuka <shadowgun@i.ua>
@OlegDokuka
OlegDokukaforce-pushed the bugfix/request_channel branch from 9ca64fe to fb97f43CompareApril 9, 2020 12:43

@rstoyanchevrstoyanchev left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good overall.

Just one minor comment below, and also checkAvailable() seems to be missing @Nullable which results in several IDE warnings in RSocketRequester.

// need to skip first since we have already sent it
first = false;
return;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The if (first) check could be replaced with inboundFlux.skip(1)?

@OlegDokukaOlegDokukaApr 9, 2020

Copy link
Copy Markdown
MemberAuthor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It was with skip initially, but, I figured out that skip does extra request(1) when it skips, so we have extra 1 element requested (I mentioned that in the comments that expected prefetch is 256, but it was 257)

The strategy is the following

  1. we do at the very beginning request(1) (from the switchOnFirst) to obtain the first element and then do the transformation.
  2. Then, we send that obtained element as a part of RequestChannel frame so it appears on the moment of delivery
  3. Then, in order to not break backpressure because of the eager first element prefetch, we reduce 1 from the first upcoming request to the switchOnFirst.
  4. However, the first prefetched element is sent to the flux along the way, and that would be OK if we have just normal routing case, but, in case of RSocket, the first payload has already been sent so if we are not going to skip the first element, it will be delivered twice
  5. Here comes the issue, if we use skip then skip operator think that we need to fulfill the demand by requesting extra one element, but in fact we just need not skip but DROP element instead without doing request(1)

@OlegDokuka
OlegDokuka merged commit 8bdaee2 into developApr 9, 2020
@rstoyanchevrstoyanchev modified the milestones: 1.0, 1.0.0-RC7Apr 17, 2020
@rstoyanchevrstoyanchev changed the title [Bugfix] Incorrect Behaviour of RequestChannel Fixes behavior of RequestChannel Apr 27, 2020
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Missing onComplete from requestChannel

4 participants

@OlegDokuka@yschimke@rstoyanchev@simonbasle