X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/2c69d491fbbd1461bb5a6dd9c0f0dd493081b45e..de4df7f80c531ab16e59ea36671a8efa9e6ff33d:/services/nodemanager/arvnodeman/daemon.py diff --git a/services/nodemanager/arvnodeman/daemon.py b/services/nodemanager/arvnodeman/daemon.py index cb11521ef9..f23b2615e2 100644 --- a/services/nodemanager/arvnodeman/daemon.py +++ b/services/nodemanager/arvnodeman/daemon.py @@ -232,7 +232,7 @@ class NodeManagerDaemonActor(actor_class): def try_pairing(self): for record in self.cloud_nodes.unpaired(): for arv_rec in self.arvados_nodes.unpaired(): - if record.actor.offer_arvados_pair(arv_rec.arvados_node).get(): + if record.actor is not None and record.actor.offer_arvados_pair(arv_rec.arvados_node).get(): self._pair_nodes(record, arv_rec.arvados_node) break @@ -243,16 +243,15 @@ class NodeManagerDaemonActor(actor_class): return s def _node_states(self, size): - states = pykka.get_all(rec.actor.get_state() - for rec in self.cloud_nodes.nodes.itervalues() - if ((size is None or rec.cloud_node.size.id == size.id) and - rec.shutdown_actor is None and - rec.actor is not None)) - states += ['shutdown' for rec in self.cloud_nodes.nodes.itervalues() - if ((size is None or rec.cloud_node.size.id == size.id) and - (rec.shutdown_actor is not None or - rec.actor is None))] - return states + proxy_states = [] + states = [] + for rec in self.cloud_nodes.nodes.itervalues(): + if size is None or rec.cloud_node.size.id == size.id: + if rec.shutdown_actor is None and rec.actor is not None: + proxy_states.append(rec.actor.get_state()) + else: + states.append("shutdown") + return states + pykka.get_all(proxy_states) def _state_counts(self, size): states = self._node_states(size) @@ -427,16 +426,25 @@ class NodeManagerDaemonActor(actor_class): @_check_poll_freshness def node_can_shutdown(self, node_actor): - if self._nodes_excess(node_actor.cloud_node.get().size) > 0: - self._begin_node_shutdown(node_actor, cancellable=True) - elif self.cloud_nodes.nodes.get(node_actor.cloud_node.get().id).arvados_node is None: - # Node is unpaired, which means it probably exceeded its booting - # grace period without a ping, so shut it down so we can boot a new - # node in its place. - self._begin_node_shutdown(node_actor, cancellable=False) - elif node_actor.in_state('down').get(): - # Node is down and unlikely to come back. - self._begin_node_shutdown(node_actor, cancellable=False) + try: + if self._nodes_excess(node_actor.cloud_node.get().size) > 0: + self._begin_node_shutdown(node_actor, cancellable=True) + elif self.cloud_nodes.nodes.get(node_actor.cloud_node.get().id).arvados_node is None: + # Node is unpaired, which means it probably exceeded its booting + # grace period without a ping, so shut it down so we can boot a new + # node in its place. + self._begin_node_shutdown(node_actor, cancellable=False) + elif node_actor.in_state('down').get(): + # Node is down and unlikely to come back. + self._begin_node_shutdown(node_actor, cancellable=False) + except pykka.ActorDeadError as e: + # The monitor actor sends shutdown suggestions every time the + # node's state is updated, and these go into the daemon actor's + # message queue. It's possible that the node has already been shut + # down (which shuts down the node monitor actor). In that case, + # this message is stale and we'll get ActorDeadError when we try to + # access node_actor. Log the error. + self._logger.debug("ActorDeadError in node_can_shutdown: %s", e) def node_finished_shutdown(self, shutdown_actor): try: