@@ -104,33 +104,46 @@ def start_with_concurrency_limit(*args)
104
104
prepend LimitConcurrentStartsInstance
105
105
end
106
106
107
- require "thread"
108
-
109
- module SSHKit
110
- module Runner
111
- class ParallelCompleteAll < Abstract
112
- def execute
113
- threads = hosts . map do |host |
114
- Thread . new ( host ) do |h |
115
- begin
116
- backend ( h , &block ) . run
117
- rescue ::StandardError => e
118
- e2 = SSHKit ::Runner ::ExecuteError . new e
119
- raise e2 , "Exception while executing #{ host . user ? "as #{ host . user } @" : "on host " } #{ host } : #{ e . message } "
120
- end
121
- end
107
+ class SSHKit ::Runner ::MultipleExecuteError < SSHKit ::StandardError
108
+ attr_reader :execute_errors
109
+
110
+ def initialize ( execute_errors )
111
+ @execute_errors = execute_errors
112
+ end
113
+ end
114
+
115
+ class SSHKit ::Runner ::Parallel
116
+ # SSHKit joins the threads in sequence and fails on the first error it encounters, which means that we wait threads
117
+ # before the first failure to complete but not for ones after.
118
+ #
119
+ # We'll patch it to wait for them all to complete, and to record all the threads that errored so we can see when a
120
+ # problem occurs on multiple hosts.
121
+ module CompleteAll
122
+ def execute
123
+ threads = hosts . map do |host |
124
+ Thread . new ( host ) do |h |
125
+ backend ( h , &block ) . run
126
+ rescue ::StandardError => e
127
+ e2 = SSHKit ::Runner ::ExecuteError . new e
128
+ raise e2 , "Exception while executing #{ host . user ? "as #{ host . user } @" : "on host " } #{ host } : #{ e . message } "
122
129
end
130
+ end
123
131
124
- exception = nil
125
- threads . each do |t |
126
- begin
127
- t . join
128
- rescue SSHKit ::Runner ::ExecuteError => e
129
- exception ||= e
130
- end
132
+ exceptions = [ ]
133
+ threads . each do |t |
134
+ begin
135
+ t . join
136
+ rescue SSHKit ::Runner ::ExecuteError => e
137
+ exceptions << e
131
138
end
132
- raise exception if exception
139
+ end
140
+ if exceptions . one?
141
+ raise exceptions . first
142
+ elsif exceptions . many?
143
+ raise SSHKit ::Runner ::MultipleExecuteError . new ( exceptions )
133
144
end
134
145
end
135
146
end
147
+
148
+ prepend CompleteAll
136
149
end
0 commit comments