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

[FIXED] Dispatching of asynchronous callbacks #369

Merged
merged 4 commits into from
Jun 12, 2018
Merged

Conversation

kozlovic
Copy link
Member

This is a follow up on #365. Working on another issue and running
tests, I still had a race on the original ach or a panic on send
to close channel.

Move from a channel to a linked list with dedicated lock.

Signed-off-by: Ivan Kozlovic [email protected]

This is a follow up on #365. Working on another issue and running
tests, I still had a race on the original ach or a panic on send
to close channel.

Move from a channel to a linked list with dedicated lock.

Signed-off-by: Ivan Kozlovic <[email protected]>
@kozlovic kozlovic requested a review from derekcollison June 12, 2018 00:55
@coveralls
Copy link

coveralls commented Jun 12, 2018

Coverage Status

Coverage decreased (-0.01%) to 95.132% when pulling 65cf3c3 on async_cb_handler into d4841f2 on master.

// Make sure that library is not calling push with nil function,
// since this is used to notify the dispatcher that it should stop.
if !close && f == nil {
panic("pushing a nil callback")
Copy link
Member

Choose a reason for hiding this comment

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

Do we have any other panics in our library?

Copy link
Member Author

Choose a reason for hiding this comment

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

This is not user accessible. This is to protect us, writers of the library. That is, to catch a case where we would add some code that happen to call push() with a nil callback (if we were not checking nc.Opts.).

nats.go Outdated
nc.mu.Unlock()
}
// Returns an initialized asyncCallbacksHandler object
func newAsyncCallbacksHandler() *asyncCallbacksHandler {
Copy link
Member

Choose a reason for hiding this comment

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

Seems to be only called once and very short, maybe just inline?

Copy link
Member Author

Choose a reason for hiding this comment

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

actually called in a test too.

if !close && f == nil {
panic("pushing a nil callback")
}
cb := &asyncCB{f: f}
Copy link
Member

Choose a reason for hiding this comment

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

if close is true does f have to be nil?

Copy link
Member Author

Choose a reason for hiding this comment

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

I originally used a closed boolean in the structure but thought that I could do without and pass nil as the last function to indicate close event. But yes, f will be nil if close is true. Again, this is not user accessible and only close() will call pushOrClose with nil, true

nats.go Outdated
ac.head = cb
}
ac.tail = cb
ac.cond.Signal()
Copy link
Member

Choose a reason for hiding this comment

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

For close scenarios I like this to be a Broadcast instead.

Copy link
Member Author

Choose a reason for hiding this comment

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

Sorry, but there is only one go routine ever calling Wait() so Signal() is enough.

Copy link
Member

Choose a reason for hiding this comment

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

I know that is the desired state. But kind of like your panic thought best to kick out any and all IMO.

Copy link
Member Author

Choose a reason for hiding this comment

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

Ok, makes sense.

ncp.Close()

// Give a chance for the go routine to stop
time.Sleep(150 * time.Millisecond)
Copy link
Member

Choose a reason for hiding this comment

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

Be good if this was deterministic instead of time based.

Copy link
Member Author

Choose a reason for hiding this comment

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

I could add specific wait group in the struct and use that for the test, but I feel it is a bit too much. What I could do is repeat the test with a little delay in case of failure and fail the test after few attempts. I will do that.

- Use Broadcast() instead of Signal()
- Presence of asyncCBDispatcher go routine less sensitive to
  timing.

Signed-off-by: Ivan Kozlovic <[email protected]>
nats.go Outdated
@@ -1605,7 +1605,7 @@ func (ac *asyncCallbacksHandler) pushOrClose(f func(), close bool) {
ac.head = cb
}
ac.tail = cb
ac.cond.Signal()
ac.cond.Broadcast()
Copy link
Member

Choose a reason for hiding this comment

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

I meant only on close condition. Signal as default is fine.

Copy link
Member Author

Choose a reason for hiding this comment

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

Done.. but to be honest, this is some code that one will scratch their head in few months/years and ask themselves: why is that? ;-)
If there is a chance that we have multiple go routines calling Wait() then it should always be Broadcast(), but that would defeat the purpose of this code anyway since it is meant to ensure that callbacks are dispatched in order.

Signed-off-by: Ivan Kozlovic <[email protected]>
@derekcollison
Copy link
Member

LGTM

@kozlovic kozlovic merged commit 93a833d into master Jun 12, 2018
@kozlovic kozlovic deleted the async_cb_handler branch June 12, 2018 15:21
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.

3 participants