Fix bug around handling of failures in `spawnWorker` calls (#87)

Fixes #86

If a worker process fails to spawn, we will now complete the work attempt that caused the process to spawn with that failure, instead of never completing the attempt at all, causing a hang, and also leaking the async exception as an unhandled exception.

We could add retry logic in the future if we want, but it is probably unlikely that trying again will work. This way the actual failure should be reliably surfaced though.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 7377326..e0ad4b3 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 1.1.1
+
+* Fix a bug where if spawnWorker threw an error, work requests would hang
+  forever instead of failing.
+
 ## 1.1.0
 
 * Add constructors with named parameters to
diff --git a/lib/src/driver/driver.dart b/lib/src/driver/driver.dart
index b395bd5..e0d57ae 100644
--- a/lib/src/driver/driver.dart
+++ b/lib/src/driver/driver.dart
@@ -120,6 +120,10 @@
           _readyWorkers.remove(worker);
           _runWorkQueue();
         });
+      }).onError<Object>((e, s) {
+        _spawningWorkers.remove(futureWorker);
+        if (attempt.responseCompleter.isCompleted) return;
+        attempt.responseCompleter.completeError(e, s);
       });
     }
     // Recursively calls itself until one of the bail out conditions are met.
diff --git a/pubspec.yaml b/pubspec.yaml
index 358f03e..425fd9b 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
 name: bazel_worker
-version: 1.1.0
+version: 1.1.1
 description: >-
   Protocol and utilities to implement or invoke persistent bazel workers.
 repository: https://github.com/dart-lang/bazel_worker
diff --git a/test/driver_test.dart b/test/driver_test.dart
index 034d75a..980ae23 100644
--- a/test/driver_test.dart
+++ b/test/driver_test.dart
@@ -139,6 +139,12 @@
       });
     });
 
+    test('handles spawnWorker failures', () async {
+      driver = BazelWorkerDriver(() async => throw StateError('oh no!'),
+          maxRetries: 0);
+      expect(driver!.doWork(WorkRequest()), throwsA(isA<StateError>()));
+    });
+
     tearDown(() async {
       await driver?.terminateWorkers();
       expect(MockWorker.liveWorkers, isEmpty);