浏览代码

Handle all exceptions

If we get back an error that wasn't an APIError, it was causing the
thread to hang. This catch all, while I appreciate feels risky to
have a catch all, is better than not catching and silently failing,
with a never ending thread.

If something worse than an APIError has gone wrong, we want to stop
the incredible journey of what we're doing.

Signed-off-by: Mazz Mosley <[email protected]>
Mazz Mosley 10 年之前
父节点
当前提交
f4a8fda283
共有 2 个文件被更改,包括 26 次插入0 次删除
  1. 7 0
      compose/utils.py
  2. 19 0
      tests/integration/service_test.py

+ 7 - 0
compose/utils.py

@@ -32,6 +32,10 @@ def parallel_execute(objects, obj_callable, msg_index, msg):
         except APIError as e:
             errors[msg_index] = e.explanation
             result = "error"
+        except Exception as e:
+            errors[msg_index] = e
+            result = 'unexpected_exception'
+
         q.put((msg_index, result))
 
     for an_object in objects:
@@ -48,6 +52,9 @@ def parallel_execute(objects, obj_callable, msg_index, msg):
     while done < total_to_execute:
         try:
             msg_index, result = q.get(timeout=1)
+
+            if result == 'unexpected_exception':
+                raise errors[msg_index]
             if result == 'error':
                 write_out_msg(stream, lines, msg_index, msg, status='error')
             else:

+ 19 - 0
tests/integration/service_test.py

@@ -654,6 +654,25 @@ class ServiceTest(DockerClientTestCase):
         self.assertTrue(service.containers()[0].is_running)
         self.assertIn("ERROR: for 2  Boom", mock_stdout.getvalue())
 
+    @patch('sys.stdout', new_callable=StringIO)
+    def test_scale_with_api_returns_unexpected_exception(self, mock_stdout):
+        """
+        Test that when scaling if the API returns an error, that is not of type
+        APIError, that error is re-raised.
+        """
+        service = self.create_service('web')
+        next_number = service._next_container_number()
+        service.create_container(number=next_number, quiet=True)
+
+        with patch(
+            'compose.container.Container.create',
+                side_effect=ValueError("BOOM")):
+            with self.assertRaises(ValueError):
+                service.scale(3)
+
+        self.assertEqual(len(service.containers()), 1)
+        self.assertTrue(service.containers()[0].is_running)
+
     @patch('compose.service.log')
     def test_scale_with_desired_number_already_achieved(self, mock_log):
         """