async enforceClusterConsistency() {
    // Delay the check to 1 heartbeat round, to allow all nodes to update
    // their ID cards
    await Bluebird.delay(this.heartbeatDelay);

    try {
      const idCards = await this.idCardHandler.getRemoteIdCards();
      idCards.push(this.idCardHandler.idCard);

      let splits = [];

      for (const idCard of idCards) {
        let topology = Array.from(idCard.topology);
        topology.push(idCard.id);

        if (topology.length !== idCards.length) {
          topology = topology.sort();
          const found = splits.some((split) => {
            if (split.length !== topology.length) {
              return false;
            }

            return split.every((id, index) => id === topology[index]);
          });

          if (!found) {
            splits.push(topology);
          }
        }
      }

      // No split detected, the cluster is consistent
      if (splits.length === 0) {
        return;
      }
      // There is at least 1 cluster split detected.
      //
      // First we elect the smallest split possible.
      // If multiple splits are eligibles, we choose amongst them the split
      // containing the youngest isolated node (isolated = the node is in this
      // split alone, and in no other splits). If no split is eligible using
      // this method, we fall back to the smallest split containing the youngest
      // node (isolated or not).
      //
      // The goal of this process is to force at least 1 node to kill itself,
      // with all nodes concluding on their own on the same list of nodes to
      // shut down.

      // First remove every non existing node from topologies
      splits = splits.map((topology) =>
        topology.filter((nodeId) => idCards.find((card) => card.id === nodeId)),
      );

      splits = splits.sort((a, b) => a.length - b.length);
      const eligibleSplits = splits.filter(
        (split) => split.length === splits[0].length,
      );

      let candidates;

      if (eligibleSplits.length === 1) {
        candidates = eligibleSplits[0];
      } else {
        // Beware: search isolated nodes in ALL the splits, not only the
        // smallest ones
        let isolatedNodes = _.xor(...splits);
        const eligibleNodes = _.uniq(_.flatten(eligibleSplits));

        isolatedNodes = _.intersection(isolatedNodes, eligibleNodes);

        const isIsolated = isolatedNodes.length > 0;

        // safety measure: this should never happen
        if (isolatedNodes.length === 0) {
          isolatedNodes = eligibleNodes;
        }

        let youngestNode;

        for (let i = 0; i < isolatedNodes.length; i++) {
          const idCard = idCards.find((card) => card.id === isolatedNodes[i]);
          if (!youngestNode || idCard.birthdate > youngestNode.birthdate) {
            youngestNode = idCard;
          }
        }

        if (isIsolated) {
          for (let i = 0; !candidates && i < eligibleSplits.length; i++) {
            if (eligibleSplits[i].includes(youngestNode.id)) {
              candidates = _.intersection(eligibleSplits[i], isolatedNodes);
            }
          }
        } else {
          candidates = [youngestNode.id];
        }
      }

      if (candidates.includes(this.nodeId)) {
        global.kuzzle.log.error(
          "[CLUSTER] Network split detected. This node is outside the cluster: shutting down.",
        );
        global.kuzzle.shutdown();
        return;
      }
    } catch (err) {
      global.kuzzle.log.error(
        "[CLUSTER] Unexpected exception caught during a cluster consistency check. Shutting down...",
      );
      global.kuzzle.log.error(err.stack);
      global.kuzzle.shutdown();
    }
  }
Verifies the consistency of the cluster by comparing our own known
topology with the one kept in other nodes ID cards

/!\ Do not wait for this method: it's meant to run as a background check.
It'll never throw, and it'll never generate unhandled rejections.