SIENTIAPDE-988
Refactor ingestor lease management and update Docker configurations - Updated CMD in Dockerfile to use the correct application entry point. - Added docker compose command to remove volumes in README. - Removed unnecessary restart policy from ingestor service in docker-compose.yaml. - Refactored manage_leases method in Ingestor class to improve clarity and parameter naming. - Added get_number_of_leases method in IngestorManager to retrieve active leases. - Implemented get_all_leases method in ResourceManager to fetch active leases from Redis. - Enhanced unit tests for lease management in test_ingestor_manager and test_resource_manager.
This commit is contained in:
@@ -27,4 +27,4 @@ RUN --mount=type=ssh \
|
|||||||
|
|
||||||
|
|
||||||
# Run the application
|
# Run the application
|
||||||
CMD ["python", "-m", "ingestor.ingestor"]
|
CMD ["python", "-m", "ingestor.app"]
|
||||||
@@ -20,6 +20,7 @@ sudo systemctl restart docker
|
|||||||
|
|
||||||
### Run docker compose
|
### Run docker compose
|
||||||
'''
|
'''
|
||||||
|
docker compose down -v
|
||||||
docker compose build --ssh default=$HOME/.ssh/id_ed25519_docker
|
docker compose build --ssh default=$HOME/.ssh/id_ed25519_docker
|
||||||
docker compose up -d
|
docker compose up -d
|
||||||
'''
|
'''
|
||||||
|
|||||||
@@ -2,7 +2,6 @@ version: '3.8'
|
|||||||
|
|
||||||
services:
|
services:
|
||||||
ingestor:
|
ingestor:
|
||||||
restart: always
|
|
||||||
build:
|
build:
|
||||||
context: .
|
context: .
|
||||||
environment:
|
environment:
|
||||||
|
|||||||
@@ -134,37 +134,38 @@ class Ingestor:
|
|||||||
|
|
||||||
self.handle_acquired_tags(acquired)
|
self.handle_acquired_tags(acquired)
|
||||||
|
|
||||||
def manage_leases(self, ingestor_diff: int, slot_diff: int):
|
def manage_leases(self, available_slots: int, lacking_ingestors: int, slot_diff: int):
|
||||||
"""
|
"""
|
||||||
Manages the allocation and deallocation of slot leases based on the
|
Manages the allocation and deallocation of slot leases for ingestors based on
|
||||||
differences in the number of active ingestors and available slots.
|
the number of available slots, lacking ingestors, and slot differences.
|
||||||
Args:
|
Args:
|
||||||
ingestor_diff (int): The difference between the required and available
|
available_slots (int): The number of slots currently available for allocation.
|
||||||
ingestors. A positive value indicates that there are inactive
|
lacking_ingestors (int): The number of ingestors that are active and without slots.
|
||||||
ingestors and available slots.
|
slot_diff (int): The difference between the total slots and the required slots.
|
||||||
slot_diff (int): The difference between the required and available
|
|
||||||
slots. A positive value indicates that there are active ingestors
|
|
||||||
without assigned slots.
|
|
||||||
Behavior:
|
Behavior:
|
||||||
- If `ingestor_diff` is greater than 0, it means there are available
|
- If there are available slots and lacking ingestors, attempts to acquire slot leases
|
||||||
slots due to inactive ingestors. The method will acquire slot leases
|
for the available slots and processes the acquired tags.
|
||||||
for the available slots and handle the acquired tags.
|
- If there are no lacking ingestors but there are extra slots (slot_diff > 0),
|
||||||
- If `slot_diff` is greater than 0, it means there are active ingestors
|
releases the extra slot leases to ensure proper allocation.
|
||||||
without slots. The method will drop slot leases for the excess
|
Logs:
|
||||||
managed tags.
|
- Logs the number of available slots when attempting to acquire leases.
|
||||||
|
- Logs the number of extra slots when releasing leases.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if ingestor_diff > 0:
|
if available_slots > 0 and lacking_ingestors > 0:
|
||||||
# Some ingestors are innactive, so theres "ingestor_diff" slots available
|
# Some ingestors are innactive, so theres "available_slots" slots available
|
||||||
self.logger.info(f"Slots available: {ingestor_diff}")
|
self.logger.info(f"Slots available: {available_slots}")
|
||||||
|
|
||||||
# Get slot lease
|
# Get slot lease
|
||||||
acquired = self.ingestor_manager.get_slot_leases(ingestor_diff)
|
acquired = self.ingestor_manager.get_slot_leases(available_slots)
|
||||||
|
|
||||||
self.handle_acquired_tags(acquired)
|
self.handle_acquired_tags(acquired)
|
||||||
|
|
||||||
elif slot_diff > 0:
|
elif lacking_ingestors == 0 and slot_diff > 0:
|
||||||
# Some ingestors are active and without slots, so we need to drop
|
|
||||||
|
self.logger.info(f"Extra slots available: {slot_diff}")
|
||||||
|
# There's enough slots for all ingestors, but this ingestor has more than one slot
|
||||||
|
# So we need to drop the extra leases
|
||||||
|
|
||||||
overleases = list(self.ingestor_manager.managed_tags.keys())[1:]
|
overleases = list(self.ingestor_manager.managed_tags.keys())[1:]
|
||||||
|
|
||||||
@@ -194,19 +195,23 @@ class Ingestor:
|
|||||||
self.logger.info("Polling for slot updates...")
|
self.logger.info("Polling for slot updates...")
|
||||||
# Get active ingestors
|
# Get active ingestors
|
||||||
ingestors = self.ingestor_manager.get_active_ingestors()
|
ingestors = self.ingestor_manager.get_active_ingestors()
|
||||||
|
number_of_ingestors = len(ingestors)
|
||||||
|
number_of_leases = self.ingestor_manager.get_number_of_leases()
|
||||||
number_of_slots = self.ingestor_manager.get_number_of_slots()
|
number_of_slots = self.ingestor_manager.get_number_of_slots()
|
||||||
|
|
||||||
# Handle no slots
|
# Handle no slots
|
||||||
self.manage_no_slots(number_of_slots)
|
self.manage_no_slots(number_of_slots)
|
||||||
|
|
||||||
ingestor_diff = number_of_slots - len(ingestors)
|
available_slots = number_of_slots - number_of_leases
|
||||||
|
lacking_ingestors = number_of_slots - number_of_ingestors
|
||||||
slot_diff = len(self.ingestor_manager.managed_tags) - 1
|
slot_diff = len(self.ingestor_manager.managed_tags) - 1
|
||||||
|
|
||||||
self.manage_leases(ingestor_diff, slot_diff)
|
self.manage_leases(available_slots, lacking_ingestors, slot_diff)
|
||||||
|
|
||||||
self.logger.info(
|
self.logger.info(
|
||||||
f"Active ingestors: {ingestors}, "
|
f"Active ingestors: {ingestors}, "
|
||||||
f"Number of slots: {number_of_slots}, "
|
f"Number of slots: {number_of_slots}, "
|
||||||
|
f"Number of leases: {number_of_leases}, "
|
||||||
f"Managed tags: {self.ingestor_manager.managed_tags}"
|
f"Managed tags: {self.ingestor_manager.managed_tags}"
|
||||||
f"Managed servers: {self.ingestor_manager.opc_managers}"
|
f"Managed servers: {self.ingestor_manager.opc_managers}"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -134,6 +134,19 @@ class IngestorManager():
|
|||||||
ingestors = self.resource_manager.get_all_ingestors()
|
ingestors = self.resource_manager.get_all_ingestors()
|
||||||
return ingestors if ingestors else []
|
return ingestors if ingestors else []
|
||||||
|
|
||||||
|
def get_number_of_leases(self) -> int:
|
||||||
|
"""
|
||||||
|
Retrieves the number of leases managed by the resource manager.
|
||||||
|
This method fetches all available leases from the resource manager,
|
||||||
|
calculates their count, and updates the `number_of_slots` attribute.
|
||||||
|
Returns:
|
||||||
|
int: The total number of leases. Returns 0 if no leases are available.
|
||||||
|
"""
|
||||||
|
|
||||||
|
leases = self.resource_manager.get_all_leases()
|
||||||
|
self.number_of_slots = len(leases) if leases else 0
|
||||||
|
return self.number_of_slots
|
||||||
|
|
||||||
def get_number_of_slots(self) -> int:
|
def get_number_of_slots(self) -> int:
|
||||||
"""
|
"""
|
||||||
Retrieves the number of slots managed by the resource manager.
|
Retrieves the number of slots managed by the resource manager.
|
||||||
|
|||||||
@@ -117,3 +117,14 @@ class ResourceManager:
|
|||||||
"""
|
"""
|
||||||
|
|
||||||
return self.redis.keys("slot:opc_tags:*")
|
return self.redis.keys("slot:opc_tags:*")
|
||||||
|
|
||||||
|
def get_all_leases(self) -> List[str]:
|
||||||
|
"""
|
||||||
|
Retrieves all active leases from Redis.
|
||||||
|
This method fetches all keys in Redis that match the pattern for OPC tag leases
|
||||||
|
and returns a list of active leases.
|
||||||
|
Returns:
|
||||||
|
list: A list of active leases.
|
||||||
|
"""
|
||||||
|
|
||||||
|
return self.redis.keys("lease:opc_tags:*")
|
||||||
|
|||||||
@@ -183,6 +183,22 @@ def test_get_active_ingestors_empty(ingestor_manager):
|
|||||||
ingestor_manager.resource_manager.get_all_ingestors.assert_called_once()
|
ingestor_manager.resource_manager.get_all_ingestors.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_number_of_leases_success(ingestor_manager):
|
||||||
|
ingestor_manager.resource_manager.get_all_leases = MagicMock(
|
||||||
|
return_value=["lease1", "lease2"])
|
||||||
|
result = ingestor_manager.get_number_of_leases()
|
||||||
|
assert result == 2
|
||||||
|
ingestor_manager.resource_manager.get_all_leases.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_number_of_leases_empty(ingestor_manager):
|
||||||
|
ingestor_manager.resource_manager.get_all_leases = MagicMock(
|
||||||
|
return_value=None)
|
||||||
|
result = ingestor_manager.get_number_of_leases()
|
||||||
|
assert result == 0
|
||||||
|
ingestor_manager.resource_manager.get_all_leases.assert_called_once()
|
||||||
|
|
||||||
|
|
||||||
def test_get_number_of_slots_success(ingestor_manager):
|
def test_get_number_of_slots_success(ingestor_manager):
|
||||||
ingestor_manager.resource_manager.get_all_slots = MagicMock(
|
ingestor_manager.resource_manager.get_all_slots = MagicMock(
|
||||||
return_value=["slot1", "slot2"])
|
return_value=["slot1", "slot2"])
|
||||||
|
|||||||
@@ -98,3 +98,12 @@ def test_get_all_slots(resource_manager):
|
|||||||
resource_manager.redis.keys.assert_called_once_with(
|
resource_manager.redis.keys.assert_called_once_with(
|
||||||
'slot:opc_tags:*'
|
'slot:opc_tags:*'
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
def test_get_all_leases(resource_manager):
|
||||||
|
resource_manager.redis.keys.return_value = ['lease1', 'lease2']
|
||||||
|
result = resource_manager.get_all_leases()
|
||||||
|
assert result == ['lease1', 'lease2']
|
||||||
|
resource_manager.redis.keys.assert_called_once_with(
|
||||||
|
'lease:opc_tags:*'
|
||||||
|
)
|
||||||
|
|||||||
@@ -155,28 +155,30 @@ def test_manage_slots_none_available_none_available(ingestor_manager_started):
|
|||||||
ingestor_manager_started.ingestor_manager.get_slot_leases.return_value)
|
ingestor_manager_started.ingestor_manager.get_slot_leases.return_value)
|
||||||
|
|
||||||
|
|
||||||
def test_manage_leases_0_0(ingestor_manager_started):
|
def test_manage_leases_no_available_slots_no_extra_slots(ingestor_manager_started):
|
||||||
ingestor_manager_started.handle_acquired_tags = MagicMock()
|
ingestor_manager_started.handle_acquired_tags = MagicMock()
|
||||||
|
|
||||||
ingestor_manager_started.manage_leases(0, 0)
|
ingestor_manager_started.manage_leases(0, 0, 0)
|
||||||
|
|
||||||
ingestor_manager_started.ingestor_manager.get_slot_leases.assert_not_called()
|
ingestor_manager_started.ingestor_manager.get_slot_leases.assert_not_called()
|
||||||
ingestor_manager_started.ingestor_manager.handle_acquired_tags.assert_not_called()
|
ingestor_manager_started.ingestor_manager.handle_acquired_tags.assert_not_called()
|
||||||
ingestor_manager_started.ingestor_manager.drop_slot_leases.assert_not_called()
|
ingestor_manager_started.ingestor_manager.drop_slot_leases.assert_not_called()
|
||||||
|
|
||||||
|
|
||||||
def test_manage_leases_innactive_ingestors(ingestor_manager_started):
|
def test_manage_leases_available_slots_innactive_ingestors(ingestor_manager_started):
|
||||||
ingestor_manager_started.handle_acquired_tags = MagicMock()
|
ingestor_manager_started.handle_acquired_tags = MagicMock()
|
||||||
|
|
||||||
ingestor_manager_started.manage_leases(2, 0)
|
ingestor_manager_started.manage_leases(2, 2, 5)
|
||||||
|
|
||||||
ingestor_manager_started.ingestor_manager.get_slot_leases.assert_called_once_with(
|
ingestor_manager_started.ingestor_manager.get_slot_leases.assert_called_once_with(
|
||||||
2)
|
2)
|
||||||
ingestor_manager_started.handle_acquired_tags.assert_called_once_with(
|
ingestor_manager_started.handle_acquired_tags.assert_called_once_with(
|
||||||
ingestor_manager_started.ingestor_manager.get_slot_leases.return_value)
|
ingestor_manager_started.ingestor_manager.get_slot_leases.return_value)
|
||||||
|
|
||||||
|
ingestor_manager_started.ingestor_manager.drop_slot_leases.assert_not_called()
|
||||||
|
|
||||||
def test_manage_leases_available_ingestors(ingestor_manager_started):
|
|
||||||
|
def test_manage_leases_no_available_slots_extra_sltos(ingestor_manager_started):
|
||||||
ingestor_manager_started.handle_acquired_tags = MagicMock()
|
ingestor_manager_started.handle_acquired_tags = MagicMock()
|
||||||
ingestor_manager_started.ingestor_manager.managed_tags = {
|
ingestor_manager_started.ingestor_manager.managed_tags = {
|
||||||
"tag1": "server1",
|
"tag1": "server1",
|
||||||
@@ -184,7 +186,7 @@ def test_manage_leases_available_ingestors(ingestor_manager_started):
|
|||||||
"tag3": "server3"
|
"tag3": "server3"
|
||||||
}
|
}
|
||||||
|
|
||||||
ingestor_manager_started.manage_leases(0, 2)
|
ingestor_manager_started.manage_leases(0, 0, 2)
|
||||||
|
|
||||||
ingestor_manager_started.ingestor_manager.get_slot_leases.assert_not_called()
|
ingestor_manager_started.ingestor_manager.get_slot_leases.assert_not_called()
|
||||||
ingestor_manager_started.handle_acquired_tags.assert_not_called()
|
ingestor_manager_started.handle_acquired_tags.assert_not_called()
|
||||||
|
|||||||
Reference in New Issue
Block a user