Although still early in its development, I enjoyed getting started with Hop last night. But I left off half way through my introduction to task management (think Makefiles) in Dart. As of last night I can start a test server with Hop:
➜ hipster-mvc git:(http-test-server) ✗ ./bin/hop test_server-startBut I have to manually lookup the the process ID (PID) so that I can kill it from the shell:
➜ hipster-mvc git:(http-test-server) ✗ ps -ef | grep test_server chris 902 1 0 Jul12 pts/23 00:00:00 /bin/sh -c 'dart' 'test/test_server.dart' chris 903 902 0 Jul12 pts/23 00:00:00 dart test/test_server.dart chris 7745 1937 0 22:50 pts/23 00:00:00 grep test_ser ➜ hipster-mvc git:(http-test-server) ✗ kill 903Let's see if I can get stopping the server under Hop as well. Currently the
test_server-start
task resolves to a Dart function that starts a shell process:Future<bool> _startTestServer(TaskContext content) { var started = new Completer(); Process. start('dart', ['test/test_server.dart'], runInShell: true). then((_)=> started.complete(true)); return started.future; }To obtain the PID of my test server, I need to use the value supplied to the
then()
method. So instead of ignoring it with the _
variable, I assign it to the a parameter named process
. A Dart Process
, which is what is supplied by the process's Future
, has a pid
process that I ought to be able to use. For now, I just print it out:Future<bool> _startTestServer(TaskContext content) { var started = new Completer(); Process. start('dart', ['test/test_server.dart'], runInShell: true). then((process) { print(process.pid); started.complete(true); }); return started.future; }But when I try that out, I find:
➜ hipster-mvc git:(http-test-server) ✗ ./bin/hop test_server-start 8267 ➜ hipster-mvc git:(http-test-server) ✗ ps -ef | grep test_server chris 8267 1 0 23:00 pts/23 00:00:00 /bin/sh -c 'dart' 'test/test_server.dart' chris 8268 8267 2 23:00 pts/23 00:00:00 dart test/test_server.dart chris 8293 1937 0 23:00 pts/23 00:00:00 grep test_serverThe
pid
process refers to the PID of the shell process which is responsible for starting my server. That ain't gonna work. If I kill the shell process that starts the server (PID of 8267
in this case), then the actual test server continues to run:➜ hipster-mvc git:(http-test-server) ✗ kill 8267 ➜ hipster-mvc git:(http-test-server) ✗ ps -ef | grep test_server chris 8268 1 0 23:00 pts/23 00:00:00 dart test/test_server.dart chris 8337 1937 0 23:00 pts/23 00:00:00 grep test_serverI suppose that I could kill
pid + 1
, but there is the edge case in which the shell process could be 32768
and the child process would be the next unused PID after 1
.No, what I need is something a bit more reliable. Now that I think about it, there is really no need to run my test server in a shell. I like shelling out and all, but in this case it seems to be causing more trouble than it is worth. So I remove the
runInShell
optional parameter from the Process.start()
method (it defaults to false
):Future<bool> _startTestServer(TaskContext content) { var started = new Completer(); Process. start('dart', ['test/test_server.dart']). then((process) { print(process.pid); started.complete(true); }); return started.future; }With that, I have the PID of the actual test server and I can kill it nice and proper:
➜ hipster-mvc git:(http-test-server) ✗ ./bin/hop test_server-start 8445 ➜ hipster-mvc git:(http-test-server) ✗ ps -ef | grep test_server chris 8445 1 3 23:05 pts/23 00:00:00 dart test/test_server.dart chris 8470 1937 0 23:05 pts/23 00:00:00 grep test_server ➜ hipster-mvc git:(http-test-server) ✗ kill 8445 ➜ hipster-mvc git:(http-test-server) ✗ ps -ef | grep test_server chris 8514 1937 0 23:05 pts/23 00:00:00 grep test_serverUnfortunately, this does me little immediate good in my efforts to easily kill the server for two reasons. First, once the Hop command successfully starts my test server, it exits. At this point, I no longer have access to the process to send it the kill message. My second problem is that, even if I write the PID to the file system so that
hop test_server-stop
could read it, Dart does not support killing arbitrary processes—I can only kill the current process or one that I start with Process.start
.First things first—I write the PID out to the filesystem:
Future<bool> _startTestServer(TaskContext content) { var started = new Completer(); Process. start('dart', ['test/test_server.dart']). then((process) { new File('test_server.pid') ..writeAsStringSync('${process.pid}'); started.complete(true); }); return started.future; }Now I need to figure out how to use that PID to kill off my running process. Well, I suppose if I cannot kill it off natively in Dart, I can run a process to do it for me.
As with my start-server process, this is asynchronous in nature—
Process.run()
returns a future that will complete when the process successfully returns. This means that I have to go through the same dance in my _stopTestServer()
function that I did in _startTestServer()
. I need to instantiate a Completer
and return its future
so that Hop will know when the task finishes. Then I run my kill process and, when its future completes, then I complete my own:Future<bool> _stopTestServer(TaskContext context) { var killed = new Completer(); var pid = new File('test_server.pid'). readAsStringSync(); Process. run('kill', [pid]). then((_)=> killed.complete(true)); return killed.future; }And that actually seems to do the trick. I can start my test server process, examine the resultant PID file to verify that it corresponds to the running test server:
➜ hipster-mvc git:(http-test-server) ✗ ./bin/hop test_server-start ➜ hipster-mvc git:(http-test-server) ✗ cat test_server.pid 8847% ➜ hipster-mvc git:(http-test-server) ✗ ps -ef | grep test_server chris 8847 1 0 23:25 pts/23 00:00:00 dart test/test_server.dart chris 8894 1937 0 23:25 pts/23 00:00:00 grep test_serverAnd, when I Hop the test_server-stop task, the test server process is, indeed, stopped:
➜ hipster-mvc git:(http-test-server) ✗ ./bin/hop test_server-stop ➜ hipster-mvc git:(http-test-server) ✗ ps -ef | grep test_server chris 8991 1937 0 23:30 pts/23 00:00:00 grep test_serverThat is not rock solid as server start and stop goes. I am doing absolutely no error handling for when I start a server when one is already running, stop a server when one is not running, etc. I am also leaving a mess behind by not deleting the
test_server.pid
file. Cleaning up the PID file is simple enough that I implement it tonight:Future<bool> _stopTestServer(TaskContext context) { var killed = new Completer(); var pid_file = new File('test_server.pid'); var pid = pid_file.readAsStringSync(); pid_file.deleteSync(); Process. run('kill', [pid]). then((_)=> killed.complete(true)); return killed.future; }But I will leave error handling for another day.
With that, I can hop start and stop my test server. Up tomorrow, I will look into replacing my current bash script that runs my test suite with Hop.
Day #811
No comments:
Post a Comment