Wednesday, August 28, 2013

Graceful Exits from Dart Processes


I have been trying to keep my “fake test” HTTP server in Dart clean. Not just the code, but the filesystem. The fake test server persists data in dart dirty, which creates a store on the filesystem. I added an onClose callback (callback?!) to the server's listen() call:
main() {
  return HttpServer.bind('127.0.0.1', 31337)..then((app) {
    app.listen((HttpRequest req) {
      // handle requests...
    },
    onDone: removeDb);
  });
}
And that works… when the server shuts down normally.

But the test runner does not allow the server to exit gracefully. It kills it:
# Start the test server
dart test/dummy_server.dart &
server_pid=$!

# Run the actual tests...

# Stop the server
kill $server_pid
This leaves a mess behind:
...
CONSOLE MESSAGE: All 10 tests passed.
CONSOLE MESSAGE: unittest-suite-success

➜  plummbur-kruk git:(master) ✗ ls test.db
test.db
In the test runner, it would be OK to manually remove the file. But this is intended to run as part of other test suites. Other test suites should not need to know how to clean up my mess.

This proves exceptionally difficult—at least my first pass at getting this to work does. There seems to be no way to listen for interrupt signals to the Dart VM (at least currently). So my option seems to be forking a process, waiting for it to be killed, and then doing something when it exits. Even that proves tricky in the confines of my test library.

I create a process.dart file as a wrapper to server.dart, which contains the current web server. In there, I use Process.start() to fork the server, then wait for the exit:
library plummbur_kruk;

import 'dart:io';

main() {
  Process.start('dart', ['lib/server.dart']).
    then((process) {
      print('pid is: ${process.pid}');
      process.
        exitCode.
        then((code) => print('died with $code'));
    });
}
When I run that in a separate script that invokes the main() method, I keep getting 255 exit codes:
died with 255
This turns out to be due to the lib in Dart Pub packages lacking a package directory of their own (because typcially this is where package symbolic links point to). For the time being, I manually add a packages subdirectory.

That allows the code to run... and to exit:
Running dart:html tests
tests: index
pid is: 11673

➜  plummbur-kruk git:(master) ✗ died with -15
The ‘died’ message comes later—after the server process was killed (but not the parent process). So, in there, I ought to be able to perform and DB / file system clean-up that I need to perform. But that feels awfully hacky. I think it best to call it a night here and ruminate on this approach and the actual use case.



Day #857

No comments:

Post a Comment