summaryrefslogtreecommitdiff
path: root/distbuild/build_controller.py
diff options
context:
space:
mode:
Diffstat (limited to 'distbuild/build_controller.py')
-rw-r--r--distbuild/build_controller.py125
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()