فهرست منبع

Fixes #1955 - Handle unexpected errors, but don't ignore background threads.

Signed-off-by: Daniel Nephin <[email protected]>
Daniel Nephin 10 سال پیش
والد
کامیت
61415cd8bc
2فایلهای تغییر یافته به همراه19 افزوده شده و 13 حذف شده
  1. 16 10
      compose/utils.py
  2. 3 3
      tests/integration/service_test.py

+ 16 - 10
compose/utils.py

@@ -21,7 +21,6 @@ def parallel_execute(objects, obj_callable, msg_index, msg):
     """
     """
     stream = get_output_stream(sys.stdout)
     stream = get_output_stream(sys.stdout)
     lines = []
     lines = []
-    errors = {}
 
 
     for obj in objects:
     for obj in objects:
         write_out_msg(stream, lines, msg_index(obj), msg)
         write_out_msg(stream, lines, msg_index(obj), msg)
@@ -29,16 +28,17 @@ def parallel_execute(objects, obj_callable, msg_index, msg):
     q = Queue()
     q = Queue()
 
 
     def inner_execute_function(an_callable, parameter, msg_index):
     def inner_execute_function(an_callable, parameter, msg_index):
+        error = None
         try:
         try:
             result = an_callable(parameter)
             result = an_callable(parameter)
         except APIError as e:
         except APIError as e:
-            errors[msg_index] = e.explanation
+            error = e.explanation
             result = "error"
             result = "error"
         except Exception as e:
         except Exception as e:
-            errors[msg_index] = e
+            error = e
             result = 'unexpected_exception'
             result = 'unexpected_exception'
 
 
-        q.put((msg_index, result))
+        q.put((msg_index, result, error))
 
 
     for an_object in objects:
     for an_object in objects:
         t = Thread(
         t = Thread(
@@ -49,15 +49,17 @@ def parallel_execute(objects, obj_callable, msg_index, msg):
         t.start()
         t.start()
 
 
     done = 0
     done = 0
+    errors = {}
     total_to_execute = len(objects)
     total_to_execute = len(objects)
 
 
     while done < total_to_execute:
     while done < total_to_execute:
         try:
         try:
-            msg_index, result = q.get(timeout=1)
+            msg_index, result, error = q.get(timeout=1)
 
 
             if result == 'unexpected_exception':
             if result == 'unexpected_exception':
-                raise errors[msg_index]
+                errors[msg_index] = result, error
             if result == 'error':
             if result == 'error':
+                errors[msg_index] = result, error
                 write_out_msg(stream, lines, msg_index, msg, status='error')
                 write_out_msg(stream, lines, msg_index, msg, status='error')
             else:
             else:
                 write_out_msg(stream, lines, msg_index, msg)
                 write_out_msg(stream, lines, msg_index, msg)
@@ -65,10 +67,14 @@ def parallel_execute(objects, obj_callable, msg_index, msg):
         except Empty:
         except Empty:
             pass
             pass
 
 
-    if errors:
-        stream.write("\n")
-        for error in errors:
-            stream.write("ERROR: for {}  {} \n".format(error, errors[error]))
+    if not errors:
+        return
+
+    stream.write("\n")
+    for msg_index, (result, error) in errors.items():
+        stream.write("ERROR: for {}  {} \n".format(msg_index, error))
+        if result == 'unexpected_exception':
+            raise error
 
 
 
 
 def get_output_stream(stream):
 def get_output_stream(stream):

+ 3 - 3
tests/integration/service_test.py

@@ -638,8 +638,7 @@ class ServiceTest(DockerClientTestCase):
         self.assertTrue(service.containers()[0].is_running)
         self.assertTrue(service.containers()[0].is_running)
         self.assertIn("ERROR: for 2  Boom", mock_stdout.getvalue())
         self.assertIn("ERROR: for 2  Boom", mock_stdout.getvalue())
 
 
-    @mock.patch('sys.stdout', new_callable=StringIO)
-    def test_scale_with_api_returns_unexpected_exception(self, mock_stdout):
+    def test_scale_with_api_returns_unexpected_exception(self):
         """
         """
         Test that when scaling if the API returns an error, that is not of type
         Test that when scaling if the API returns an error, that is not of type
         APIError, that error is re-raised.
         APIError, that error is re-raised.
@@ -650,7 +649,8 @@ class ServiceTest(DockerClientTestCase):
 
 
         with mock.patch(
         with mock.patch(
             'compose.container.Container.create',
             'compose.container.Container.create',
-                side_effect=ValueError("BOOM")):
+            side_effect=ValueError("BOOM")
+        ):
             with self.assertRaises(ValueError):
             with self.assertRaises(ValueError):
                 service.scale(3)
                 service.scale(3)