[IMP] maintenance_service_http_monitoring : speed up KO confirmation
Some checks failed
pre-commit / pre-commit (pull_request) Has been cancelled
Some checks failed
pre-commit / pre-commit (pull_request) Has been cancelled
The previous design required two passes of the 10-minute sweep before a maintenance request was created, so an outage took at least ~10 extra minutes (up to 20) to be reported. Split the monitoring into two crons with distinct responsibilities: - the 10-minute sweep only discovers outages, flags the KO streak via ``http_first_ko_at`` and auto-resolves recovered services; - a new 2-minute confirmation cron re-checks only the flagged services and creates a request once the service has been continuously KO for ``HTTP_KO_CONFIRMATION_DELAY`` (lowered from 5 to 2 minutes). This keeps the transient-outage filter while removing the extra sweep latency. Services already under an open request are skipped by the confirmation cron and remain handled by the sweep.
This commit is contained in:
@@ -12,8 +12,8 @@ EQUIPMENT_HTTP_REQUESTS = (
|
||||
".models.maintenance_equipment.http_requests"
|
||||
)
|
||||
|
||||
# Comfortably past HTTP_KO_CONFIRMATION_DELAY (currently 10 minutes).
|
||||
PAST_CONFIRMATION_DELAY = timedelta(minutes=20)
|
||||
# Comfortably past HTTP_KO_CONFIRMATION_DELAY (currently 2 minutes).
|
||||
PAST_CONFIRMATION_DELAY = timedelta(minutes=10)
|
||||
|
||||
|
||||
def _mock_response(status_code):
|
||||
@@ -42,7 +42,7 @@ class TestHttpMonitoring(TransactionCase):
|
||||
)
|
||||
|
||||
def _backdate_first_ko(self, *service_instances):
|
||||
"""Simulate that the current KO streak started long enough ago to be confirmed."""
|
||||
"""Simulate a KO streak old enough ago to be confirmed."""
|
||||
for service_instance in service_instances:
|
||||
service_instance.write(
|
||||
{"http_first_ko_at": fields.Datetime.now() - PAST_CONFIRMATION_DELAY}
|
||||
@@ -81,7 +81,7 @@ class TestHttpMonitoring(TransactionCase):
|
||||
with patch(SERVICE_INSTANCE_REQUESTS) as mock_requests:
|
||||
mock_requests.get.return_value = _mock_response(500)
|
||||
mock_requests.exceptions.RequestException = Exception
|
||||
self.env["service.instance"].cron_check_http_services()
|
||||
self.env["service.instance"].cron_confirm_http_ko_services()
|
||||
|
||||
request = self.service_instance.http_maintenance_request
|
||||
self.assertTrue(request)
|
||||
@@ -118,16 +118,19 @@ class TestHttpMonitoring(TransactionCase):
|
||||
with patch(SERVICE_INSTANCE_REQUESTS) as mock_requests:
|
||||
mock_requests.get.return_value = _mock_response(500)
|
||||
mock_requests.exceptions.RequestException = Exception
|
||||
self.env["service.instance"].cron_check_http_services() # confirmed, request created
|
||||
# confirmed -> request created
|
||||
self.env["service.instance"].cron_confirm_http_ko_services()
|
||||
|
||||
request_1 = self.service_instance.http_maintenance_request
|
||||
self.assertTrue(request_1)
|
||||
|
||||
with patch(SERVICE_INSTANCE_REQUESTS) as mock_requests:
|
||||
mock_requests.get.return_value = _mock_response(500)
|
||||
mock_requests.exceptions.RequestException = Exception
|
||||
self.env["service.instance"].cron_check_http_services() # still KO
|
||||
# already handled -> skipped
|
||||
self.env["service.instance"].cron_confirm_http_ko_services()
|
||||
|
||||
# Service already has an open request -> the confirmation cron skips it
|
||||
mock_requests.get.assert_not_called()
|
||||
self.assertEqual(self.service_instance.http_maintenance_request, request_1)
|
||||
self.assertEqual(
|
||||
self.env["maintenance.request"].search_count(
|
||||
@@ -222,7 +225,7 @@ class TestHttpMonitoring(TransactionCase):
|
||||
):
|
||||
mock_requests.get.return_value = _mock_response(500)
|
||||
mock_requests.exceptions.RequestException = Exception
|
||||
self.env["service.instance"].cron_check_http_services()
|
||||
self.env["service.instance"].cron_confirm_http_ko_services()
|
||||
|
||||
mock_http.post.assert_called_once()
|
||||
call_kwargs = mock_http.post.call_args
|
||||
@@ -249,7 +252,7 @@ class TestHttpMonitoring(TransactionCase):
|
||||
):
|
||||
mock_requests.get.return_value = _mock_response(500)
|
||||
mock_requests.exceptions.RequestException = Exception
|
||||
self.env["service.instance"].cron_check_http_services()
|
||||
self.env["service.instance"].cron_confirm_http_ko_services()
|
||||
|
||||
self.assertTrue(self.service_instance.http_maintenance_request)
|
||||
mock_http.post.assert_not_called()
|
||||
@@ -283,7 +286,7 @@ class TestHttpMonitoring(TransactionCase):
|
||||
with patch(SERVICE_INSTANCE_REQUESTS) as mock_requests:
|
||||
mock_requests.get.return_value = _mock_response(200)
|
||||
mock_requests.exceptions.RequestException = Exception
|
||||
self.env["service.instance"].cron_check_http_services()
|
||||
self.env["service.instance"].cron_confirm_http_ko_services()
|
||||
|
||||
self.assertTrue(self.service_instance.http_status_ok)
|
||||
self.assertEqual(self.service_instance.last_http_status_code, 200)
|
||||
@@ -314,7 +317,7 @@ class TestHttpMonitoring(TransactionCase):
|
||||
with patch(SERVICE_INSTANCE_REQUESTS) as mock_requests:
|
||||
mock_requests.get.return_value = _mock_response(503)
|
||||
mock_requests.exceptions.RequestException = Exception
|
||||
self.env["service.instance"].cron_check_http_services()
|
||||
self.env["service.instance"].cron_confirm_http_ko_services()
|
||||
|
||||
self.assertEqual(mock_requests.get.call_count, 1)
|
||||
self.assertFalse(self.service_instance.http_status_ok)
|
||||
@@ -345,7 +348,7 @@ class TestHttpMonitoring(TransactionCase):
|
||||
with patch(SERVICE_INSTANCE_REQUESTS) as mock_requests:
|
||||
mock_requests.get.return_value = _mock_response(500)
|
||||
mock_requests.exceptions.RequestException = Exception
|
||||
self.env["service.instance"].cron_check_http_services()
|
||||
self.env["service.instance"].cron_confirm_http_ko_services()
|
||||
|
||||
req1 = self.service_instance.http_maintenance_request
|
||||
req2 = service_instance2.http_maintenance_request
|
||||
@@ -374,11 +377,11 @@ class TestHttpMonitoring(TransactionCase):
|
||||
|
||||
self._backdate_first_ko(self.service_instance)
|
||||
|
||||
# Second cron run: streak confirmed -> request created
|
||||
# Confirmation cron run: streak confirmed -> request created
|
||||
with patch(SERVICE_INSTANCE_REQUESTS) as mock_requests:
|
||||
mock_requests.get.return_value = _mock_response(500)
|
||||
mock_requests.exceptions.RequestException = Exception
|
||||
self.env["service.instance"].cron_check_http_services()
|
||||
self.env["service.instance"].cron_confirm_http_ko_services()
|
||||
|
||||
request = self.service_instance.http_maintenance_request
|
||||
self.assertTrue(request)
|
||||
@@ -411,3 +414,55 @@ class TestHttpMonitoring(TransactionCase):
|
||||
# Calling close directly must not raise
|
||||
self.service_instance._close_http_maintenance_request()
|
||||
self.assertFalse(self.service_instance.http_maintenance_request)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Test 17 -- Confirmation cron ignores services without a KO streak
|
||||
# ------------------------------------------------------------------
|
||||
def test_confirmation_cron_ignores_unflagged_services(self):
|
||||
with patch(SERVICE_INSTANCE_REQUESTS) as mock_requests:
|
||||
mock_requests.get.return_value = _mock_response(200)
|
||||
mock_requests.exceptions.RequestException = Exception
|
||||
self.env["service.instance"].cron_confirm_http_ko_services()
|
||||
|
||||
mock_requests.get.assert_not_called()
|
||||
self.assertFalse(self.service_instance.http_maintenance_request)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Test 18 -- Confirmation cron does not create a request before
|
||||
# HTTP_KO_CONFIRMATION_DELAY has elapsed
|
||||
# ------------------------------------------------------------------
|
||||
def test_confirmation_cron_waits_for_confirmation_delay(self):
|
||||
with patch(SERVICE_INSTANCE_REQUESTS) as mock_requests:
|
||||
mock_requests.get.return_value = _mock_response(500)
|
||||
mock_requests.exceptions.RequestException = Exception
|
||||
self.env["service.instance"].cron_check_http_services()
|
||||
|
||||
self.assertTrue(self.service_instance.http_first_ko_at)
|
||||
|
||||
with patch(SERVICE_INSTANCE_REQUESTS) as mock_requests:
|
||||
mock_requests.get.return_value = _mock_response(500)
|
||||
mock_requests.exceptions.RequestException = Exception
|
||||
self.env["service.instance"].cron_confirm_http_ko_services()
|
||||
|
||||
self.assertFalse(self.service_instance.http_maintenance_request)
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# Test 19 -- Confirmation cron ignores services whose equipment is in
|
||||
# maintenance mode
|
||||
# ------------------------------------------------------------------
|
||||
def test_confirmation_cron_skips_maintenance_mode(self):
|
||||
with patch(SERVICE_INSTANCE_REQUESTS) as mock_requests:
|
||||
mock_requests.get.return_value = _mock_response(500)
|
||||
mock_requests.exceptions.RequestException = Exception
|
||||
self.env["service.instance"].cron_check_http_services()
|
||||
|
||||
self.assertTrue(self.service_instance.http_first_ko_at)
|
||||
self.equipment.write({"maintenance_mode": True})
|
||||
|
||||
with patch(SERVICE_INSTANCE_REQUESTS) as mock_requests:
|
||||
mock_requests.get.return_value = _mock_response(500)
|
||||
mock_requests.exceptions.RequestException = Exception
|
||||
self.env["service.instance"].cron_confirm_http_ko_services()
|
||||
|
||||
mock_requests.get.assert_not_called()
|
||||
self.assertFalse(self.service_instance.http_maintenance_request)
|
||||
|
||||
Reference in New Issue
Block a user