def _build_retain_slots(self, cluster: Cluster, slots: Optional[Dict[str, int]]) -> Optional[List[str]]:
        """Handle retention policy of physical replication slots for cluster members.

        When the member key is missing we want to keep its replication slot for a while, so that WAL segments
        will not be already absent when it comes back online. It is being solved by storing the list of
        replication slots representing members in the ``retain_slots`` field of the ``/status`` key.

        This method handles retention policy by keeping the list of such replication slots in memory
        and removing names when they were observed longer than ``member_slots_ttl`` ago.

        :param cluster: :class:`Cluster` object with information about the current cluster state.
        :param slots: slot names with LSN values that exist on the leader node and consists
                      of slots for cluster members and permanent replication slots.

        :returns: the list of replication slots to be written to ``/status`` key or ``None``.
        """
        timestamp = time.time()

        if slots:  # if slots is not empty it implies we are running v11+
            members: Set[str] = set()
            found_self = False
            for member in cluster.members:
                found_self = member.name == self._name
                if not member.nostream:
                    members.add(slot_name_from_member_name(member.name))
            if not found_self:
                # It could be that the member key for our node is not in DCS and we can't check tags.nostream.
                # In this case our name will falsely appear in `retain_slots`, but only temporary.
                members.add(slot_name_from_member_name(self._name))

            permanent_slots = cluster.permanent_physical_slots
            # we want to have in ``retain_slots`` only non-permanent member slots
            self._last_retain_slots.update({name: timestamp for name in slots
                                            if name in members and name not in permanent_slots})
        # retention
        for name, value in list(self._last_retain_slots.items()):
            if value + global_config.member_slots_ttl <= timestamp:
                logger.info("Replication slot '%s' for absent cluster member is expired after %d sec.",
                            name, global_config.member_slots_ttl)
                del self._last_retain_slots[name]

        return list(sorted(self._last_retain_slots.keys())) or None
Handle retention policy of physical replication slots for cluster members.

        When the member key is missing we want to keep its replication slot for a while, so that WAL segments
        will not be already absent when it comes back online. It is being solved by storing the list of
        replication slots representing members in the ``retain_slots`` field of the ``/status`` key.

        This method handles retention policy by keeping the list of such replication slots in memory
        and removing names when they were observed longer than ``member_slots_ttl`` ago.

        :param cluster: :class:`Cluster` object with information about the current cluster state.
        :param slots: slot names with LSN values that exist on the leader node and consists
                      of slots for cluster members and permanent replication slots.

        :returns: the list of replication slots to be written to ``/status`` key or ``None``.
        
patroni/dcs/__init__.py