Skip to content

Commit

Permalink
Complete channel initialization in the event loop
Browse files Browse the repository at this point in the history
If addLast is called outside an event loop, then the handler is added in
the 'pending' state. Sending an event to the pipeline does not send it
to the last handler, but to the last _non-pending_ handler. We therefore
have to make sure to involve the event loop _before_ marking the channel
as ready to be used.

Thanks to @Reflexe who pointed me in the right direction.

Fixes #7464.

Closes #7509.

GERRIT_CHANGE_ID=
PiperOrigin-RevId: 235184010
  • Loading branch information
ulfjack authored and copybara-github committed Feb 22, 2019
1 parent 17794d5 commit f9eb1b5
Showing 1 changed file with 20 additions and 2 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,16 @@ private Channel acquireUploadChannel() throws InterruptedException {
p.addLast(new HttpUploadHandler(creds));
}

channelReady.setSuccess(ch);
if (!ch.eventLoop().inEventLoop()) {
// If addLast is called outside an event loop, then it doesn't complete until the
// event loop is run again. In that case, a message sent to the last handler gets
// delivered to the last non-pending handler, which will most likely end up
// throwing UnsupportedMessageTypeException. Therefore, we only complete the
// promise in the event loop.
ch.eventLoop().execute(() -> channelReady.setSuccess(ch));
} else {
channelReady.setSuccess(ch);
}
} catch (Throwable t) {
channelReady.setFailure(t);
}
Expand Down Expand Up @@ -332,7 +341,16 @@ private Future<Channel> acquireDownloadChannel() {
p.addLast(new HttpDownloadHandler(creds));
}

channelReady.setSuccess(ch);
if (!ch.eventLoop().inEventLoop()) {
// If addLast is called outside an event loop, then it doesn't complete until the
// event loop is run again. In that case, a message sent to the last handler gets
// delivered to the last non-pending handler, which will most likely end up
// throwing UnsupportedMessageTypeException. Therefore, we only complete the
// promise in the event loop.
ch.eventLoop().execute(() -> channelReady.setSuccess(ch));
} else {
channelReady.setSuccess(ch);
}
} catch (Throwable t) {
channelReady.setFailure(t);
}
Expand Down

0 comments on commit f9eb1b5

Please sign in to comment.