diff options
Diffstat (limited to 'distbuild/build_controller.py')
-rw-r--r-- | distbuild/build_controller.py | 125 |
1 files changed, 71 insertions, 54 deletions
diff --git a/distbuild/build_controller.py b/distbuild/build_controller.py index 8b9f34e7..ed6c424e 100644 --- a/distbuild/build_controller.py +++ b/distbuild/build_controller.py @@ -155,74 +155,81 @@ class BuildController(distbuild.StateMachine): _idgen = distbuild.IdentifierGenerator('BuildController') - def __init__(self, build_request_message, artifact_cache_server, - morph_instance): + def __init__(self, initiator_connection, build_request_message, + artifact_cache_server, morph_instance): distbuild.crash_point() distbuild.StateMachine.__init__(self, 'init') + self._initiator_connection = initiator_connection self._request = build_request_message self._artifact_cache_server = artifact_cache_server self._morph_instance = morph_instance self._helper_id = None - self.debug_transitions = True + self.debug_transitions = False + + def __repr__(self): + return '<BuildController at 0x%x, request-id %s>' % (id(self), + self._request['id']) def setup(self): distbuild.crash_point() spec = [ + # state, source, event_class, new_state, callback ('init', self, _Start, 'graphing', self._start_graphing), - ('init', distbuild.InitiatorConnection, - distbuild.InitiatorDisconnect, 'init', self._maybe_abort), - ('init', self, _Abort, None, None), - + ('init', self._initiator_connection, + distbuild.InitiatorDisconnect, None, None), + ('graphing', distbuild.HelperRouter, distbuild.HelperOutput, - 'graphing', self._collect_graph), + 'graphing', self._maybe_collect_graph), ('graphing', distbuild.HelperRouter, distbuild.HelperResult, - 'graphing', self._finish_graph), + 'graphing', self._maybe_finish_graph), ('graphing', self, _GotGraph, 'annotating', self._start_annotating), ('graphing', self, _GraphFailed, None, None), - ('graphing', distbuild.InitiatorConnection, - distbuild.InitiatorDisconnect, None, - self._maybe_abort), - + ('graphing', self._initiator_connection, + distbuild.InitiatorDisconnect, None, None), + ('annotating', distbuild.HelperRouter, distbuild.HelperResult, - 'annotating', self._handle_cache_response), + 'annotating', self._maybe_handle_cache_response), ('annotating', self, _AnnotationFailed, None, self._notify_annotation_failed), ('annotating', self, _Annotated, 'building', self._queue_worker_builds), - ('annotating', distbuild.InitiatorConnection, - distbuild.InitiatorDisconnect, None, - self._maybe_abort), - - ('building', distbuild.WorkerConnection, - distbuild.WorkerBuildStepStarted, 'building', - self._relay_build_step_started), - ('building', distbuild.WorkerConnection, - distbuild.WorkerBuildOutput, 'building', - self._relay_build_output), - ('building', distbuild.WorkerConnection, - distbuild.WorkerBuildCaching, 'building', - self._relay_build_caching), - ('building', distbuild.WorkerConnection, - distbuild.WorkerBuildFinished, 'building', - self._check_result_and_queue_more_builds), - ('building', distbuild.WorkerConnection, - distbuild.WorkerBuildFailed, None, - self._notify_build_failed), + ('annotating', self._initiator_connection, + distbuild.InitiatorDisconnect, None, None), + + # The exact WorkerConnection that is doing our building changes + # from build to build. We must listen to all messages from all + # workers, and choose whether to change state inside the callback. + # (An alternative would be to manage a set of temporary transitions + # specific to WorkerConnection instances that our currently + # building for us, but the state machines are not intended to + # behave that way). + ('building', distbuild.WorkerConnection, + distbuild.WorkerBuildStepStarted, 'building', + self._maybe_relay_build_step_started), + ('building', distbuild.WorkerConnection, + distbuild.WorkerBuildOutput, 'building', + self._maybe_relay_build_output), + ('building', distbuild.WorkerConnection, + distbuild.WorkerBuildCaching, 'building', + self._maybe_relay_build_caching), + ('building', distbuild.WorkerConnection, + distbuild.WorkerBuildFinished, 'building', + self._maybe_check_result_and_queue_more_builds), + ('building', distbuild.WorkerConnection, + distbuild.WorkerBuildFailed, 'building', + self._maybe_notify_build_failed), + ('building', self, _Abort, None, None), ('building', self, _Built, None, self._notify_build_done), - ('building', distbuild.InitiatorConnection, - distbuild.InitiatorDisconnect, 'building', + ('building', self._initiator_connection, + distbuild.InitiatorDisconnect, None, self._notify_initiator_disconnected), ] self.add_transitions(spec) self.mainloop.queue_event(self, _Start()) - def _maybe_abort(self, event_source, event): - if event.id == self._request['id']: - self.mainloop.queue_event(self, _Abort()) - def _start_graphing(self, event_source, event): distbuild.crash_point() @@ -248,14 +255,14 @@ class BuildController(distbuild.StateMachine): progress = BuildProgress(self._request['id'], 'Computing build graph') self.mainloop.queue_event(BuildController, progress) - def _collect_graph(self, event_source, event): + def _maybe_collect_graph(self, event_source, event): distbuild.crash_point() if event.msg['id'] == self._helper_id: self._artifact_data.add(event.msg['stdout']) self._artifact_error.add(event.msg['stderr']) - def _finish_graph(self, event_source, event): + def _maybe_finish_graph(self, event_source, event): distbuild.crash_point() def notify_failure(msg_text): @@ -333,7 +340,7 @@ class BuildController(distbuild.StateMachine): logging.debug('Made cache request for state of artifacts ' '(helper id: %s)' % self._helper_id) - def _handle_cache_response(self, event_source, event): + def _maybe_handle_cache_response(self, event_source, event): logging.debug('Got cache response: %s' % repr(event.msg)) def set_status(artifact): @@ -423,11 +430,12 @@ class BuildController(distbuild.StateMachine): def _notify_initiator_disconnected(self, event_source, disconnect): - if disconnect.id == self._request['id']: - cancel = BuildCancel(disconnect.id) - self.mainloop.queue_event(BuildController, cancel) + logging.debug("BuildController %r: initiator id %s disconnected", self, + disconnect.id) + cancel = BuildCancel(disconnect.id) + self.mainloop.queue_event(BuildController, cancel) - def _relay_build_step_started(self, event_source, event): + def _maybe_relay_build_step_started(self, event_source, event): distbuild.crash_point() if event.initiator_id != self._request['id']: return # not for us @@ -445,7 +453,7 @@ class BuildController(distbuild.StateMachine): self.mainloop.queue_event(BuildController, started) logging.debug('BC: emitted %s' % repr(started)) - def _relay_build_output(self, event_source, event): + def _maybe_relay_build_output(self, event_source, event): distbuild.crash_point() if event.msg['id'] != self._request['id']: return # not for us @@ -463,7 +471,7 @@ class BuildController(distbuild.StateMachine): self.mainloop.queue_event(BuildController, output) logging.debug('BC: queued %s' % repr(output)) - def _relay_build_caching(self, event_source, event): + def _maybe_relay_build_caching(self, event_source, event): distbuild.crash_point() if event.initiator_id != self._request['id']: return # not for us @@ -486,7 +494,7 @@ class BuildController(distbuild.StateMachine): else: return None - def _check_result_and_queue_more_builds(self, event_source, event): + def _maybe_check_result_and_queue_more_builds(self, event_source, event): distbuild.crash_point() if event.msg['id'] != self._request['id']: return # not for us @@ -526,17 +534,24 @@ class BuildController(distbuild.StateMachine): failed = BuildFailed(self._request['id'], errmsg) self.mainloop.queue_event(BuildController, failed) - def _notify_build_failed(self, event_source, event): + def _maybe_notify_build_failed(self, event_source, event): distbuild.crash_point() + if event.msg['id'] != self._request['id']: - return # not for us + return artifact = self._find_artifact(event.artifact_cache_key) + if artifact is None: - # This is not the event you are looking for. - return + logging.error( + 'BuildController %r: artifact %s is not in our build graph!', + self, artifact) + # We abort the build in this case on the grounds that something is + # very wrong internally, and it's best for the initiator to receive + # an error than to be left hanging. + self.mainloop.queue_event(self, _Abort()) - logging.error( + logging.info( 'Build step failed for %s: %s', artifact.name, repr(event.msg)) step_failed = BuildStepFailed( @@ -561,6 +576,8 @@ class BuildController(distbuild.StateMachine): cancel = BuildCancel(self._request['id']) self.mainloop.queue_event(BuildController, cancel) + self.mainloop.queue_event(self, _Abort()) + def _notify_build_done(self, event_source, event): distbuild.crash_point() |