Code review comment: That's not the most important thing this block is trying to accomplish:  It's making sure an up-to-date node is fetched from node repo, mutated, and saved back, all under the application lock.  This avoid overwriting fields others may have modified on the node since above.

Code under review:
void retireAllocated() {
        List<Node> allNodes = nodeRepository().getNodes(NodeType.tenant);
        List<ApplicationId> activeApplications = getActiveApplicationIds(allNodes);
        Map<Flavor, Map<Node.State, Long>> numSpareNodesByFlavorByState = getNumberOfNodesByFlavorByNodeState(allNodes);
        flavorSpareChecker.updateReadyAndActiveCountsByFlavor(numSpareNodesByFlavorByState);

        
        Map<Deployment, Set<Node>> nodesToRetireByDeployment = new HashMap<>();
        for (ApplicationId applicationId : activeApplications) {
            List<Node> applicationNodes = getNodesBelongingToApplication(allNodes, applicationId);
            Set<Node> retireableNodes = getRetireableNodesForApplication(applicationNodes);
            long numNodesAllowedToRetire = getNumberNodesAllowToRetireForApplication(applicationNodes, MAX_SIMULTANEOUS_RETIRES_PER_APPLICATION);
            if (retireableNodes.isEmpty() || numNodesAllowedToRetire == 0) continue;

            Optional<Deployment> deployment = deployer.deployFromLocalActive(applicationId, Duration.ofMinutes(30));
            if ( ! deployment.isPresent()) continue; 

            Set<Node> replaceableNodes = retireableNodes.stream()
                    .filter(node -> flavorSpareChecker.canRetireAllocatedNodeWithFlavor(node.flavor()))
                    .limit(numNodesAllowedToRetire)
                    .collect(Collectors.toSet());
            if (! replaceableNodes.isEmpty()) nodesToRetireByDeployment.put(deployment.get(), replaceableNodes);
        }

        
        
        nodesToRetireByDeployment.forEach(((deployment, nodes) -> {
            ApplicationId app = nodes.iterator().next().allocation().get().owner();
            Set<Node> nodesToRetire;

            try (Mutex lock = nodeRepository().lock(app)) {
                nodesToRetire = nodes.stream()
                        .map(node ->
                                nodeRepository().getNode(node.hostname())
                                        .filter(upToDateNode -> node.state() == Node.State.active)
                                        .filter(upToDateNode -> node.allocation().get().owner().equals(upToDateNode.allocation().get().owner())))
                        .flatMap(node -> node.map(Stream::of).orElseGet(Stream::empty))
                        .collect(Collectors.toSet());

                nodesToRetire.forEach(node -> {
                    log.info("Setting wantToRetire and wantToDeprovision for host " + node.hostname() +
                            " with flavor " + node.flavor().name() +
                            " allocated to " + node.allocation().get().owner() + ". Policy: " +
                            retirementPolicy.getClass().getSimpleName());
                    Node updatedNode = node.with(node.status()
                            .withWantToRetire(true)
                            .withWantToDeprovision(true));
                    nodeRepository().write(updatedNode);
                });
            }

            if (! nodesToRetire.isEmpty()) deployment.activate();
        }));
    }


Revised code:
void retireAllocated() {
        List<Node> allNodes = nodeRepository().getNodes(NodeType.tenant);
        List<ApplicationId> activeApplications = getActiveApplicationIds(allNodes);
        Map<Flavor, Map<Node.State, Long>> numSpareNodesByFlavorByState = getNumberOfNodesByFlavorByNodeState(allNodes);
        flavorSpareChecker.updateReadyAndActiveCountsByFlavor(numSpareNodesByFlavorByState);

        
        Map<Deployment, Set<Node>> nodesToRetireByDeployment = new HashMap<>();
        for (ApplicationId applicationId : activeApplications) {
            List<Node> applicationNodes = getNodesBelongingToApplication(allNodes, applicationId);
            Set<Node> retireableNodes = getRetireableNodesForApplication(applicationNodes);
            long numNodesAllowedToRetire = getNumberNodesAllowToRetireForApplication(applicationNodes, MAX_SIMULTANEOUS_RETIRES_PER_APPLICATION);
            if (retireableNodes.isEmpty() || numNodesAllowedToRetire == 0) continue;

            Optional<Deployment> deployment = deployer.deployFromLocalActive(applicationId, Duration.ofMinutes(30));
            if ( ! deployment.isPresent()) continue; 

            Set<Node> replaceableNodes = retireableNodes.stream()
                    .filter(node -> flavorSpareChecker.canRetireAllocatedNodeWithFlavor(node.flavor()))
                    .limit(numNodesAllowedToRetire)
                    .collect(Collectors.toSet());
            if (! replaceableNodes.isEmpty()) nodesToRetireByDeployment.put(deployment.get(), replaceableNodes);
        }

        nodesToRetireByDeployment.forEach(((deployment, nodes) -> {
            ApplicationId app = nodes.iterator().next().allocation().get().owner();
            Set<Node> nodesToRetire;

            
            
            
            try (Mutex lock = nodeRepository().lock(app)) {
                nodesToRetire = nodes.stream()
                        .map(node ->
                                nodeRepository().getNode(node.hostname())
                                        .filter(upToDateNode -> node.state() == Node.State.active)
                                        .filter(upToDateNode -> node.allocation().get().owner().equals(upToDateNode.allocation().get().owner())))
                        .flatMap(node -> node.map(Stream::of).orElseGet(Stream::empty))
                        .collect(Collectors.toSet());

                nodesToRetire.forEach(node -> {
                    log.info("Setting wantToRetire and wantToDeprovision for host " + node.hostname() +
                            " with flavor " + node.flavor().name() +
                            " allocated to " + node.allocation().get().owner() + ". Policy: " +
                            retirementPolicy.getClass().getSimpleName());
                    Node updatedNode = node.with(node.status()
                            .withWantToRetire(true)
                            .withWantToDeprovision(true));
                    nodeRepository().write(updatedNode);
                });
            }

            
            if (! nodesToRetire.isEmpty()) deployment.activate();
        }));
    }