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

QFJ-885 Send logout message before stopping initiators #101

Conversation

alphafoobar
Copy link

Because logout sets a flag indicating we should logout, we rely on another thread to send the logout message.

If we stop the initiators first that doesn't happen.

See JIRA: (QFJ-885)[http://www.quickfixj.org/jira/browse/QFJ-885]

Because logout sets a flag indicating we should logout, we rely on another thread to send the logout message.

If we stop the initiators first that doesn't happen.

See JIRA: (QFJ-885)[http://www.quickfixj.org/jira/browse/QFJ-885]
@alphafoobar alphafoobar changed the title Send logout message before stopping initiators QFJ-885 Send logout message before stopping initiators Feb 24, 2017
logoutAllSessions(forceDisconnect);
stopSessionTimer();
Copy link
Author

Choose a reason for hiding this comment

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

This is probably superfluous, since stopInitiators() will call this anyway.

Copy link
Member

@chrjohn chrjohn Feb 25, 2017

Choose a reason for hiding this comment

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

Yeah, call to stopSessionTimer() has been removed in 5f36509
And stopInitiators() was also added in that commit, but it seems it would have been better to move it below the logoutAllSessions() call.

logoutAllSessions(forceDisconnect);
stopSessionTimer();
if (!forceDisconnect) {
waitForLogout();
Copy link
Author

Choose a reason for hiding this comment

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

This isn't required because logoutAllSessions(forceDisconnect) does exactly the same, unless the sessions weren't initialised... in which case any point waiting for logout?

Copy link
Member

Choose a reason for hiding this comment

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

You are right, it is not necessary.

@chrjohn
Copy link
Member

chrjohn commented Feb 25, 2017

Hi @alphafoobar
Thanks for the PR. I'll have a look.
I recall doing the same changes on a private branch but there was some unit test failing afterwards. Will check again.
Cheers,
Chris.

@chrjohn chrjohn added this to the QFJ 1.6.4 milestone Feb 25, 2017
@alphafoobar
Copy link
Author

Hi @chrjohn
NP, I'll take a look at what unit testing is around this. If I didn't break one, then I should add one.
Cheers,
James

@chrjohn
Copy link
Member

chrjohn commented Feb 26, 2017

Hi @alphafoobar , regarding the unit test: I checked it and there was no existing test failing but one that I wrote to check for the correct behaviour. But I did not get around to correct the problem due to time constraints.

However, there have to be more changes to correct the problem since you were only changing the ThreadedSocketInitiator. But the problems were reported against the default SocketInitiator.
Did you observe the problematic behaviour only with the ThreadedSocketInitiator or did you not try with the default SocketInitiator?

Thanks,
Chris.

@alphafoobar
Copy link
Author

Hi @chrjohn,

Thanks for checking, we only use the ThreadedSocketInitiator.

Cheers
James

alphafoobar added 6 commits February 27, 2017 23:46
This allows the logout message to be generated and sent. Otherwise `stopHandlingMessages` enqueues the `END_OF_STREAM` message.

See JIRA: (QFJ-885)[http://www.quickfixj.org/jira/browse/QFJ-885]
Incorporating peer review feedback.
These comments are specifically related to the test

> SingleThreadedEventHandlingStrategyTest.shouldCleanUpInitiatorQFJMessageProcessorThreadAfterStop:248 : TestTimedOut

The call to stopHandlingMessages should happen after calling logout. Otherwise a logout message won't be sent.

```java
logoutAllSessions(forceDisconnect);
stopInitiators();
eventHandlingStrategy.stopHandlingMessages();
```

Assuming sessions have connected, this refactor is fine. When sessions do not connect as per this test, the `initialize` method (which ends up waiting for a connection) blocks the eventual call to `stop`, since both are mostly guarded by `this`.
Since it would require further refactoring of the SocketInitiator.
@alphafoobar
Copy link
Author

Hi @chrjohn

I have added some unit testing that shows a logout is happening, I was able to add those tests onto an unpatched branch and show that a logout was not sent.

I also looked at adding this for the SocketInitiator as I saw this does class does exhibit the same symptoms. But that appears to require more work for the acceptance tests to work, so I backed that change out.

Thanks,
James

@chrjohn
Copy link
Member

chrjohn commented Feb 28, 2017

Thanks @alphafoobar , I will take a look shortly.

alphafoobar added 2 commits March 4, 2017 20:47
Without posting the END_OF_STREAM message which is responsible for disconnecting the session connector
and prevent the processing of the LOGOUT message and any others that might be queued.

JIRA: QFJ-885
@alphafoobar alphafoobar force-pushed the bugfix/QFJ-885-Send-logout-message-on-shutdown branch from 259507f to 7ce6b02 Compare March 4, 2017 23:29
Following the same approach as the SocketInitiator.

JIRA: QFJ-885
@alphafoobar alphafoobar force-pushed the bugfix/QFJ-885-Send-logout-message-on-shutdown branch from 15d087b to 439c21d Compare March 5, 2017 00:01
@chrjohn
Copy link
Member

chrjohn commented Mar 6, 2017

Hi @alphafoobar, does your build run successfully with this changes? I have several unit test failures, e.g. in SocketInitiatorTest.testDoubleStartOfInitiator.
Thanks,
Chris.

@alphafoobar
Copy link
Author

Hi @chrjohn,

Sorry about that, I am seeing that unit test fail. I'll look into why that's happening.

Cheers,
James

alphafoobar added 2 commits March 7, 2017 00:18
This change pulls the stopHandlingMessages method out of the synchronized block.

Using the stop first pattern seems to let the Acceptor's QFJ Message Processing thread to linger.

JIRA: QFJ-885
@alphafoobar
Copy link
Author

Hi @chrjohn,

With the changes in this PR, the QFJ Message Processor threads weren't dying as quickly. So the problem wasn't that SocketInitiatorTest.testDoubleStartOfInitiator had initiated two sessions; but instead that the others tests may still have had lingering Acceptor threads.

Sending the END_OF_STREAM message before the synchronization block is good for emptying the message queue, but not quite as good for closing the collection quickly.

Since the acceptor change is breaking tests I've backed it out.

Cheers,
James

@chrjohn
Copy link
Member

chrjohn commented Mar 9, 2017

Hi @alphafoobar , thanks for your input. I am thinking about relaxing the synchronization around the start()/stop() methods of the Initiator to prevent the deadlock when stopHandlingMessages() is called on an Initiator in the block() method. The synchronization is merely done so that you cannot call stop() and start() concurrently. However, the SingleThreadedEventHandlingStrategy itself already checks if there already is a message processing thread active and throws an Exception in that case.

What do you think?
Cheers,
Chris.

@alphafoobar
Copy link
Author

Hi @chrjohn

It sounds sensible, starting and stopping the initiator/acceptors are activities that are unlikely to see much contention and the ThreadedSocketInitiator start/stop methods aren't synchronized.

I've been thinking that it would make more sense for the blocking thread to add the END_OF_STREAM message on the end of the queue once it realises it has been stopped, for example in SingleThreadedEventHandlingStrategy.block():

if (!eventQueue.isEmpty()) {
    final List<SessionMessageEvent> tempList = new ArrayList<>();
    eventQueue.drainTo(tempList);
    for (SessionMessageEvent event : tempList) {
        event.processMessage();
    }
    for (Session quickfixSession : sessionConnector.getManagedSessions()) {
        new SessionMessageEvent(quickfixSession, END_OF_STREAM).processMessage();
    }
}

I'm happy to help,
James

@chrjohn
Copy link
Member

chrjohn commented Apr 6, 2017

Hi @alphafoobar ,
after reviewing your changes again, I think I found an easier (i.e. less invasive) way to correct the behaviour.
One part of the solution were definitely the changes in https://github.com/quickfix-j/quickfixj/pull/101/files#diff-76633e507f7b944754a248ac2d00434c
Will check again and come back.
Thanks,
Chris.

@alphafoobar
Copy link
Author

Hi Chris, sounds good. Cheers!

@chrjohn
Copy link
Member

chrjohn commented Apr 11, 2017

Hi @alphafoobar,
I have created a new pull request #109 based on your changes. After fiddling around with your pull request and doing some other changes it was a bit of a mess. ;) So I hope it is OK with you to close this PR and that #109 resolves your issues.
Thanks for all your help and cheers,
Chris.

@chrjohn chrjohn closed this Apr 11, 2017
chrjohn added a commit that referenced this pull request Apr 12, 2017
QFJ-885 Logout message is not sent out
 - based on #101 by @alphafoobar
chrjohn added a commit that referenced this pull request Apr 12, 2017
QFJ-885 Logout message is not sent out
 - based on #101 by @alphafoobar
(cherry picked from commit 916f260)
@alphafoobar
Copy link
Author

Cool, thanks @chrjohn !

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

2 participants