11package gov .healthit .chpl .scheduler .job .urluptime ;
22
33import java .time .DayOfWeek ;
4+ import java .time .Duration ;
45import java .time .Instant ;
56import java .time .LocalDate ;
67import java .time .LocalDateTime ;
3031import gov .healthit .chpl .domain .CertificationBody ;
3132import gov .healthit .chpl .domain .Developer ;
3233import gov .healthit .chpl .exception .ValidationException ;
34+ import io .github .bucket4j .Bucket ;
3335import lombok .extern .log4j .Log4j2 ;
3436
3537@ Log4j2 (topic = "serviceBaseUrlListUptimeCreatorJobLogger" )
3638@ Component
3739public class DatadogUrlUptimeSynchonizer {
3840 private static final Long DAYS_TO_LOOK_BACK_FOR_RESULTS = 7L ;
41+ private static final long DATADOG_REQUESTS_PER_MINUTE = 90 ; //the actual limit is 100 but I don't feel like we need to cut it that close
42+ private static final long DATADOG_REQUESTS_BURST_LIMIT = 5 ;
3943
4044 // VARIABLE NAMING CONVENTION
4145 // ServiceBaseUrlList - these are service base url lists collected from the listings in CHPL, grouped by developer
4246 // DatadogSyntheticsTest - these are synthetic tests that exist in Datadog
43- // UrlUptimeMonitor - these are reporting entities that are store in the table url_uptime_monitors
47+ // UrlUptimeMonitor - these are reporting entities that are store in the table url_uptime_monitor
4448
4549 private DatadogSyntheticsTestService datadogSyntheticsTestService ;
4650 private DatadogSyntheticsTestResultService datadogSyntheticsTestResultService ;
4751 private ServiceBaseUrlListService serviceBaseUrlListService ;
4852 private UrlUptimeMonitorDAO urlUptimeMonitorDAO ;
4953 private UrlUptimeMonitorTestDAO urlUptimeMonitorTestDAO ;
5054 private DeveloperSearchService developerSearchService ;
55+ private Bucket bucket ;
5156
5257 private List <String > errorsToIgnore ;
5358
@@ -61,7 +66,16 @@ public DatadogUrlUptimeSynchonizer(DatadogSyntheticsTestService datadogSynthetic
6166 this .urlUptimeMonitorDAO = urlUptimeMonitorDAO ;
6267 this .urlUptimeMonitorTestDAO = urlUptimeMonitorTestDAO ;
6368 this .developerSearchService = developerSearchService ;
64-
69+ this .bucket = Bucket .builder ()
70+ // 1. Sustained Limit: 90 requests per 1 minute
71+ .addLimit (limit -> limit
72+ .capacity (DATADOG_REQUESTS_PER_MINUTE )
73+ .refillGreedy (DATADOG_REQUESTS_PER_MINUTE , Duration .ofMinutes (1 )))
74+ // 2. Burst Limit: Maximum 5 requests per 1 second
75+ .addLimit (limit -> limit
76+ .capacity (DATADOG_REQUESTS_BURST_LIMIT )
77+ .refillGreedy (DATADOG_REQUESTS_BURST_LIMIT , Duration .ofSeconds (1 )))
78+ .build ();
6579 errorsToIgnore = List .of ("BODY_TOO_LARGE_TO_PROCESS" );
6680 }
6781
@@ -82,12 +96,18 @@ private void synchronizeUrlUptimeMonitorTestsWithDatadogSyntheticsTestResults()
8296 .forEach (testDate -> urlUptimeMonitorDAO .getAll ().forEach (urlUptimeMonitor -> {
8397 String publicId = getDatadogPublicId (syntheticsTestDetails , urlUptimeMonitor .getUrl (), urlUptimeMonitor .getDeveloper ().getId ());
8498 datadogSyntheticsTestResultService .getSyntheticsTestResults (publicId , testDate ).forEach (syntheticsTestResult -> {
99+ try {
100+ //Blocks until tokens for BOTH limits are available
101+ bucket .asBlocking ().consumeUninterruptibly (1 );
85102 urlUptimeMonitorTestDAO .create (UrlUptimeMonitorTest .builder ()
86103 .urlUptimeMonitorId (urlUptimeMonitor .getId ())
87104 .datadogTestKey (syntheticsTestResult .getResultId ())
88105 .checkTime (toLocalDateTime (syntheticsTestResult .getCheckTime ().longValue ()))
89106 .passed (calculatePassed (syntheticsTestResult , publicId ))
90107 .build ());
108+ } catch (Exception ex ) {
109+ LOGGER .error ("Could not process url_uptime_monitor " + publicId + " for url " + urlUptimeMonitor .getUrl () + " and developer " + urlUptimeMonitor .getDeveloper ().getId ());
110+ }
91111 });
92112 }));
93113 }
@@ -97,7 +117,7 @@ private boolean calculatePassed(SyntheticsAPITestResultShort result, String publ
97117 return true ;
98118 } else {
99119 SyntheticsAPITestResultFull detailedResult = datadogSyntheticsTestResultService .getDetailedTestResult (publicId , result .getResultId ());
100- return isErrorIgnorable (detailedResult .getResult ().getFailure ().getCode ());
120+ return detailedResult != null && isErrorIgnorable (detailedResult .getResult ().getFailure ().getCode ());
101121 }
102122 }
103123
@@ -199,7 +219,7 @@ private void removeOutdatedUrlMonitors(List<UrlUptimeMonitor> existing, List<Url
199219 existing .stream ()
200220 .filter (uum -> !contains (expected , uum ))
201221 .forEach (urlMonitor -> {
202- LOGGER .info ("Removing the following URL to url_uptime_monitor table: {}, {}" , urlMonitor .getUrl (), urlMonitor .getDeveloper ().getId ());
222+ LOGGER .info ("Removing the following URL to url_uptime_monitor table: {}, {}, {} " , urlMonitor .getUrl (), urlMonitor .getDeveloper ().getId (), urlMonitor . getDatadogPublicId ());
203223 urlUptimeMonitorDAO .delete (urlMonitor );
204224 });
205225 }
0 commit comments