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

Provide a non-blocking process implementation #60

Merged
merged 1 commit into from
Aug 18, 2017

Conversation

huntc
Copy link
Contributor

@huntc huntc commented Aug 12, 2017

Utilises NuProcess in order to provide a non-blocking process implementation for Windows, OS X and Linux.

Authors: @longshorej and @huntc

@huntc
Copy link
Contributor Author

huntc commented Aug 14, 2017

@ktoso ... in case you're interested in reviewing further :-)

@longshorej ... in case you're interested integrating with our code base - we'll need to cherry pick changes to an Akka 2.4 flavour of this lib though (shouldn't be hard).

@longshorej
Copy link
Contributor

Branch created @ https://github.com/typesafehub/akka-contrib-extra/tree/3.0, I'll backport this PR once merged.

* @param stderr a `akka.stream.scaladsl.Source[ByteString]` for the standard error stream of the process
*/
case class Started(
pid: Long,
Copy link
Contributor

@longshorej longshorej Aug 14, 2017

Choose a reason for hiding this comment

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

I think pid: Int -- NuProcess.getPID() returns an int

On second thought, ignore.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, I was influenced here by the forthcoming JDK process API (which we'll probably never use!)

@huntc huntc force-pushed the nuprocess branch 3 times, most recently from d49f01d to 7d16a09 Compare August 15, 2017 07:15
@huntc
Copy link
Contributor Author

huntc commented Aug 15, 2017

Hey, @viktorklang - would you care to review - I think this PR would be right up your alley. :-)

@huntc huntc force-pushed the nuprocess branch 3 times, most recently from 0b6eb29 to 31d9460 Compare August 15, 2017 07:45
@huntc
Copy link
Contributor Author

huntc commented Aug 15, 2017

Tests are failing fairly consistently on Travis with:

[info] - should read from stdin and write to stdout *** FAILED ***
[info]   java.lang.AssertionError: assertion failed: timeout (6 seconds) during expectMsg:
...
[info]   at akka.contrib.process.NonBlockingProcessSpec$$anonfun$1$$anonfun$apply$mcV$sp$4.apply(NonBlockingProcessSpec.scala:39)

I don't seem to be able to reproduce this locally. I've enhanced the test build config to cut out parallelism etc. but still no cigar...

@huntc
Copy link
Contributor Author

huntc commented Aug 15, 2017

Update on #60 (comment)

I can reproduce this problem with reasonable consistency on Linux - harder to reproduce when invoking the "read from stdin and write to stdout" test, but not impossible. There may still be something racey about my custom graph...

@huntc
Copy link
Contributor Author

huntc commented Aug 16, 2017

@longshorej I've disabled that test you added a while back in the interest of pushing this forward. Would you mind re-visiting that test? It isn't making much sense to me. For starters, the test declares, "detect when a process has exited of its own accord", but it isn't - a Destroy is being sent...

@huntc
Copy link
Contributor Author

huntc commented Aug 17, 2017

@longshorej I’ve re-instated that test of yours for NonBlockingProcess and implemented the polling on /proc. Unfortunately, the test fails on Linux (passing just fine on OS X). I’ve run out of time today, but I was wondering if you could continue taking a look at it...

*/
class NonBlockingProcess(
command: immutable.Seq[String],
directory: File,
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we take a Path instead and thus fully be using java.nio for everything?

}
val isRunning = process.isRunning match {
case true if hasProcDir => procDirAlive(process.getPID)(contextMat, implicitly)
case result => Future.successful(result)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

We weren't handling non-Linux scenarios. :-)

@@ -20,36 +21,37 @@ class BlockingProcessSpec extends WordSpec with Matchers with BeforeAndAfterAll

implicit val system = ActorSystem("test", testConfig)

implicit val processCreationTimeout = Timeout(2.seconds)
implicit val processCreationTimeout = Timeout(2.seconds.dilated)
Copy link
Contributor Author

Choose a reason for hiding this comment

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

In case we ever declare a test timeout factor

val stdinInput = List("abcd", "1234", "quit")
val receiver = system.actorOf(Props(new Receiver(probe.ref, command, stdinInput, 1)), "receiver1")
val receiver = system.actorOf(Props(new Receiver(streamProbe.ref, exitProbe.ref, command, stdinInput, 1)), "receiver1")
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Introduced the distinction between stream and exit probes as it is technically possible to get an exit prior to the stream data

@@ -20,36 +21,37 @@ class BlockingProcessSpec extends WordSpec with Matchers with BeforeAndAfterAll

implicit val system = ActorSystem("test", testConfig)

implicit val processCreationTimeout = Timeout(2.seconds)
implicit val processCreationTimeout = Timeout(2.seconds.dilated)

"A BlockingProcess" should {
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Some small fixes to the blocking tests here.

case NonBlockingProcess.Exited(255) => true
case _ => false
case NonBlockingProcess.Exited(_) => true
case _ => false
Copy link
Contributor Author

Choose a reason for hiding this comment

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

In the case of non-Linux - we can get any non zero code.

process ! NonBlockingProcess.Destroy

exitProbe.fishForMessage() {
case NonBlockingProcess.Exited(s) if s != 0 => true
Copy link
Contributor Author

Choose a reason for hiding this comment

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

In the case of non-proc checking, we can get any non-zero

Utilises NuProcess in order to provide a non-blocking process implementation for Windows, OS X and Linux.

We've also modified some of the blocking tests in order to improve their robustness.
@huntc huntc changed the title WIP - DO NOT MERGE - Provide a non-blocking process implementation Provide a non-blocking process implementation Aug 18, 2017
Copy link
Contributor

@longshorej longshorej left a comment

Choose a reason for hiding this comment

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

Nice!

@huntc huntc merged commit f24ec4c into typesafehub:master Aug 18, 2017
@huntc huntc deleted the nuprocess branch August 18, 2017 01:22
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