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

Add a way to signal when a Channel has closed #718

Merged
merged 1 commit into from
Oct 4, 2018
Merged

Conversation

witriew
Copy link
Contributor

@witriew witriew commented Oct 2, 2018

Channel has Close() and Closed() methods that tells a Channel to close
and returns whether the Channel is already closed, respectively. This
adds a CloseChan() that returns a channel that will close once the
Channel has completed closing.

@@ -294,6 +294,9 @@ func (ts *TestServer) addChannel(createChannel func(t testing.TB, opts *ChannelO
func (ts *TestServer) close(ch *tchannel.Channel) {
ch.Close()
ts.waitForChannelClose(ch)
Copy link
Contributor

Choose a reason for hiding this comment

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

can we replace the waitForChannelClose with a select statement on the channel instead? The select should have a timeout as well.

we should remove all existing loops where we wait for close with the channel instead

@codecov
Copy link

codecov bot commented Oct 3, 2018

Codecov Report

Merging #718 into dev will increase coverage by 0.81%.
The diff coverage is 100%.

Impacted file tree graph

@@            Coverage Diff             @@
##              dev     #718      +/-   ##
==========================================
+ Coverage   86.92%   87.73%   +0.81%     
==========================================
  Files          40       40              
  Lines        4060     4068       +8     
==========================================
+ Hits         3529     3569      +40     
+ Misses        407      377      -30     
+ Partials      124      122       -2
Impacted Files Coverage Δ
channel.go 90% <100%> (+1.93%) ⬆️
outbound.go 85.05% <0%> (-1.15%) ⬇️
peer.go 94.18% <0%> (+0.72%) ⬆️
connection.go 86.6% <0%> (+3.72%) ⬆️
root_peer_list.go 96% <0%> (+4%) ⬆️
introspection.go 95.71% <0%> (+4.28%) ⬆️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 3da7066...10bdac1. Read the comment docs.

channel.go Outdated

ch.mutable.Lock()
select {
case <-ch.mutable.closed:
Copy link
Contributor

Choose a reason for hiding this comment

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

Do we need this check, I think onClosed is guaranteed to only happen once right?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I thought so too, but it looks like it's called from both Close and connectionCloseStateChange.

And the tests appear to fail if I don't guard it.

channel.go Outdated
@@ -281,6 +282,7 @@ func NewChannel(serviceName string, opts *ChannelOptions) (*Channel, error) {
}
ch.mutable.state = ChannelClient
ch.mutable.conns = make(map[uint32]*Connection)
ch.mutable.closed = make(chan struct{})
Copy link
Contributor

Choose a reason for hiding this comment

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

why is closed mutable? I think it's immutable (set on channel creation) and should only ever be closed once

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Makes sense. Moved it out of mutable.

channel.go Outdated
@@ -758,6 +760,16 @@ func (ch *Channel) connectionCloseStateChange(c *Connection) {

func (ch *Channel) onClosed() {
removeClosedChannel(ch)

ch.mutable.Lock()
Copy link
Contributor

Choose a reason for hiding this comment

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

see above, don't think this is mutable or needs a lock

ts.waitForChannelClose(ch)

select {
case <-time.After(500 * time.Millisecond):
Copy link
Contributor

Choose a reason for hiding this comment

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

  • use testutils.Timeout -- the value should be scaled up in slwoer environments.
  • The previous code did 60 iterations, each iteration taking i * 100 microseconds. i think this means we waited 100 microseconds * (1 + 2 + 3 + ... 60). That ends up being roughly 1800 * 100 microseconds or 180ms. This is a slight bump up (probably needed because we weren't using testutils.Timeout. I'm OK with keeping this higher, but can we test if 200ms works OK?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I tried this with 250ms and it was still failing, https://travis-ci.org/uber/tchannel-go/builds/436414905.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Errrp.. looks like I missed

export TEST_TIMEOUT_SCALE=20

Sounds like 200ms should work and then the Travis scaling should let it work.


select {
case <-time.After(500 * time.Millisecond):
ts.Errorf("Channel %p did not close after 500 ms, last state: %v", ch, ch.State())
Copy link
Contributor

Choose a reason for hiding this comment

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

once we use Timeout(500ms), we might want to use the same value here

@witriew witriew force-pushed the topic/wit/closechan branch 2 times, most recently from 1ac7f7a to 86f0a2b Compare October 3, 2018 18:59
Copy link
Contributor

@prashantv prashantv left a comment

Choose a reason for hiding this comment

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

Looks pretty good, just one comment on the onClosed logic

channel.go Outdated

select {
case <-ch.closed:
// Do nothing if already closed.
Copy link
Contributor

Choose a reason for hiding this comment

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

Why would it already be closed? Only if we have a bug right? We can either:

  • always close (which would panic in prod if we closed an already closed channel). since channels aren't created dynamically anyway, this seems OK
  • log an error if the channel's already closed

channel.go Outdated
@@ -266,6 +267,8 @@ func NewChannel(serviceName string, opts *ChannelOptions) (*Channel, error) {
ch.handler = channelHandler{ch}
}

ch.closed = make(chan struct{})
Copy link
Contributor

Choose a reason for hiding this comment

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

can you add this field to the channel constructor,

  closed: make(chan struct{}),

Channel has Close() and Closed() methods that tells a Channel to close
and returns whether the Channel is already closed, respectively.  This
adds a CloseChan() that returns a channel that will close once the
Channel has completed closing.
@witriew witriew merged commit b641db2 into dev Oct 4, 2018
@witriew witriew deleted the topic/wit/closechan branch October 4, 2018 00:06
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.

2 participants