Skip to content

Fix: OPS hangs when external engine errors/exits unexpectedly - #913

Merged
dwhswenson merged 4 commits into
openpathsampling:masterfrom
oliverdutton:master
Dec 23, 2020
Merged

dwhswenson merged 4 commits into
openpathsampling:masterfrom
oliverdutton:master

Conversation

@oliverdutton

Copy link
Copy Markdown
Contributor

Problem: I was using GROMACS and OPS couldn't tell when GROMACS had exited due to errors.

Reason: External engine get's checked if it's still running using subprocess.Popen.process.is_running() call. This doesn't actually communicate with the process to ask if it's still running, it returns the value corresponding to last time it was checked. In this case, when the process was set up, so case of not running never gets called.

Solution: Altered to use subprocess.Popen.process.poll() - return None is process still running, and the return code if it isn't.

I've also altered the stop signal to copy with the process already having exited of it's own accord

Problem: I was using GROMACS and OPS couldn't tell when GROMACS had exited due to errors.

Reason: External engine get's checked if it's still running using subprocess.Popen.process.is_running() call. This doesn't actually communicate with the process to ask if it's still running, it returns the value corresponding to last time it was checked. In this case, when the process was set up, so case of not running never gets called.

Solution: Altered to use subprocess.Popen.process.poll() - return None is process still running, and the return code if it isn't. 

I've also altered the stop signal to copy with the process already having exited of it's own accord
@dwhswenson dwhswenson added the bugfix PRs fixing bugs label May 2, 2020

@dwhswenson dwhswenson left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Thanks for the contribution!

I had seen this error before (when bad Gromacs input was given) but I hadn't tracked down the problem. Based on your solution, it looks like the issue is that when external engines crash due to an error, they remain in zombie status. From the docs for psutil, is_running will return True if the process is a zombie.

I expect I thought that the advantage of using is_running over poll was that is_running will give the correct value even if the process id has been reassigned to a new process. However, if the pid is held by a zombie, I don't think this will be a concern (if in the future we find that this is a problem, the if criteria could use both conditions).

The one thing that is missing here is an addition to unit tests. This would basically be a test using the slow test engine where you start the engine, manually send it a killsig, and expect that getting the next frame will raise the RuntimeError. @oliverdutton : let me know whether you want to add that or would prefer me to. (I don't know how much experience you have writing tests with pytest.) The relevant test suite is in openpathsampling/tests/test_external_engine.py.

(Also, I'll change the name of the PR -- that's because the PR title shows up in our release notes, so I'll change it to express what I think users need to know.)

@dwhswenson dwhswenson changed the title External engine communicating exit Fix: OPS hangs when external engine errors/exits unexpectedly May 2, 2020
@oliverdutton

Copy link
Copy Markdown
Contributor Author

Ah, that explains it. I wasn't entirely sure what .is_running was doing. Zombies explain it.

I don't have lots of experience with unittests so I'll leave it to you if that's okay.

…e not aligned.

int added when choosing frame as half the len of trajectory
current snapshot only set if trajectory has length (not death on creation)
@dwhswenson

Copy link
Copy Markdown
Member

Sorry for the delay on this; I meant to come back and add tests myself. Life got busy. Then it looks like a few accidental commits got added to this branch, and I was going to try to figure out how to deal with them. Life got busier. Regarding those extra commits:

  • 855f0fb keeping (though note that this functionality will be deprecated and replaced in 2.0; it's too high-level of a question for the low-level code)
  • 2914fac keeping: @hejung, I think that you are also working on something similar? heads-up that this is going into master
  • c2d47f0 will revert; in favor of the implementation included in Reactive flux (updated PR) #924

@dwhswenson
dwhswenson merged commit c6095fd into openpathsampling:master Dec 23, 2020
@dwhswenson dwhswenson mentioned this pull request Dec 23, 2020
@dwhswenson

Copy link
Copy Markdown
Member

will revert; in favor of the implementation included in #924

Oops, I meant #787. Right author; wrong PR.

@dwhswenson dwhswenson mentioned this pull request Dec 23, 2020
@oliverdutton

Copy link
Copy Markdown
Contributor Author

Wonderful.

@hejung

hejung commented Dec 23, 2020

Copy link
Copy Markdown
Contributor

Sorry for the delay on this; I meant to come back and add tests myself. Life got busy. Then it looks like a few accidental commits got added to this branch, and I was going to try to figure out how to deal with them. Life got busier. Regarding those extra commits:

* [855f0fb](https://github.com/openpathsampling/openpathsampling/commit/855f0fba950f840af00061143c695705f11ea3ea) keeping (though note that this functionality will be deprecated and replaced in 2.0; it's too high-level of a question for the low-level code)

* [2914fac](https://github.com/openpathsampling/openpathsampling/commit/2914fac642048fcefc521888307442096cf5dade) keeping: @hejung, I think that you are also working on something similar? heads-up that this is going into master

You mean the mdp parsing I guess? This should be easy to rebase/merge, I didn't touch the write_frame function :)
However looking at the commit I was wondering if the snapshot timestep is a property that all external engines have, i.e. is there anything that hinders us to put it in the ExternalEngine properties dict?
And just as a matter of curiosity: what is the corner case we catch with the nested asarray calls? list of iterators? (numpy-doc claims it should be able to convert lists of lists, lists of tuples and lists of arrays.)

* [c2d47f0](https://github.com/openpathsampling/openpathsampling/commit/c2d47f055712bc339356ffe9701e4de74375f116) will revert; in favor of the implementation included in #924

@dwhswenson

Copy link
Copy Markdown
Member

You mean the mdp parsing I guess? This should be easy to rebase/merge, I didn't touch the write_frame function :)

Yep; glad it doesn't cause any headaches!

However looking at the commit I was wondering if the snapshot timestep is a property that all external engines have, i.e. is there anything that hinders us to put it in the ExternalEngine properties dict?

Good point; completely reasonable to move that into the ExternalEngine. (In fact, I think it should be a property that all engines have, period. Defaults to 1, but this is used in, e.g., flux calculations. For OpenMM, it carries units, so your rates etc. are reported with correct units as well.)

And just as a matter of curiosity: what is the corner case we catch with the nested asarray calls? list of iterators? (numpy-doc claims it should be able to convert lists of lists, lists of tuples and lists of arrays.)

@oliverdutton : Do you recall the reason for this? I had assumed it might be something weird with simtk.unit stuff, but that isn't used for Gromacs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bugfix PRs fixing bugs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants