Repository: rucio/rucio

Issue:
The Reaper should not have a hard dependency on any RSE limits
Motivation
----------

https://github.com/rucio/rucio/blob/2ad9d0bd4a93c88b2bbd57d3679e8ff4b0607f75/lib/rucio/daemons/reaper/reaper.py#L319-L324

Otherwise, the Reaper won’t even delete obsolete replicas unless in greedy configuration.

Modification
------------

If the `MinFreeSpace` RSE limit cannot be found, then `0` should be considered its default value.



Discussion:

Resolving patch:
diff --git a/lib/rucio/core/rse.py b/lib/rucio/core/rse.py
--- a/lib/rucio/core/rse.py
+++ b/lib/rucio/core/rse.py
@@ -39,6 +39,7 @@
 import json
 from io import StringIO
 from re import match
+from typing import TYPE_CHECKING
 
 import sqlalchemy
 import sqlalchemy.orm
@@ -59,6 +60,10 @@
 from rucio.db.sqla.constants import RSEType
 from rucio.db.sqla.session import read_session, transactional_session, stream_session
 
+if TYPE_CHECKING:
+    from typing import Dict, Optional
+    from sqlalchemy.orm import Session
+
 REGION = make_region().configure('dogpile.cache.memcached',
                                  expiration_time=3600,
                                  arguments={'url': config_get('cache', 'url', False, '127.0.0.1:11211'),
@@ -709,7 +714,8 @@ def get_rse_usage(rse_id, source=None, session=None, per_account=False):
 
 
 @transactional_session
-def set_rse_limits(rse_id, name, value, session=None):
+def set_rse_limits(rse_id: str, name: str, value: int,
+                   session: 'Session' = None) -> bool:
     """
     Set RSE limits.
 
@@ -727,7 +733,8 @@ def set_rse_limits(rse_id, name, value, session=None):
 
 
 @read_session
-def get_rse_limits(rse_id, name=None, session=None):
+def get_rse_limits(rse_id: str, name: 'Optional[str]' = None,
+                   session: 'Session' = None) -> 'Dict[str, int]':
     """
     Get RSE limits.
 
@@ -740,14 +747,12 @@ def get_rse_limits(rse_id, name=None, session=None):
     query = session.query(models.RSELimit).filter_by(rse_id=rse_id)
     if name:
         query = query.filter_by(name=name)
-    limits = {}
-    for limit in query:
-        limits[limit.name] = limit.value
-    return limits
+    return {limit.name: limit.value for limit in query}
 
 
 @transactional_session
-def delete_rse_limits(rse_id, name=None, session=None):
+def delete_rse_limits(rse_id: str, name: 'Optional[str]' = None,
+                      session: 'Session' = None) -> None:
     """
     Delete RSE limit.
 
diff --git a/lib/rucio/daemons/reaper/reaper.py b/lib/rucio/daemons/reaper/reaper.py
--- a/lib/rucio/daemons/reaper/reaper.py
+++ b/lib/rucio/daemons/reaper/reaper.py
@@ -43,6 +43,7 @@
 from collections import OrderedDict
 from datetime import datetime, timedelta
 from math import ceil
+from typing import TYPE_CHECKING
 
 from dogpile.cache import make_region
 from dogpile.cache.api import NO_VALUE
@@ -69,6 +70,9 @@
 from rucio.core.vo import list_vos
 from rucio.rse import rsemanager as rsemgr
 
+if TYPE_CHECKING:
+    from typing import Callable, Tuple
+
 GRACEFUL_STOP = threading.Event()
 
 REGION = make_region().configure('dogpile.cache.memcached',
@@ -293,7 +297,8 @@ def get_max_deletion_threads_by_hostname(hostname):
     return result
 
 
-def __check_rse_usage(rse, rse_id, greedy=False, logger=logging.log):
+def __check_rse_usage(rse: str, rse_id: str, greedy: bool = False,
+                      logger: 'Callable' = logging.log) -> 'Tuple[int, bool]':
     """
     Internal method to check RSE usage and limits.
 
@@ -318,12 +323,7 @@ def __check_rse_usage(rse, rse_id, greedy=False, logger=logging.log):
 
         # Get RSE limits
         limits = get_rse_limits(rse_id=rse_id)
-        if not limits and 'MinFreeSpace' not in limits:
-            result = (needed_free_space, False)
-            REGION.set('rse_usage_%s' % rse_id, result)
-            return result
-
-        min_free_space = limits.get('MinFreeSpace')
+        min_free_space = limits.get('MinFreeSpace', 0)
 
         # Check from which sources to get used and total spaces
         # Default is storage


Test patch: