PrometheusBasedResourceLimitChecks implements ResourceLimitChecks { long calculateEffectiveLimit( final Instant effectiveSince, final Instant targetDateTime, final String periodType, final long configuredLimit) { Objects.requireNonNull(effectiveSince, "effective since"); Objects.requireNonNull(targetDateTime, "target date-time"); Objects.requireNonNull(periodType, "period mode"); if (targetDateTime.isBefore(effectiveSince)) { return 0; } if (ResourceLimitsPeriod.PERIOD_MODE_MONTHLY.equals(periodType) && configuredLimit > 0) { final ZonedDateTime effectiveSinceZonedDateTime = ZonedDateTime.ofInstant(effectiveSince, ZoneOffset.UTC); final ZonedDateTime targetZonedDateTime = ZonedDateTime.ofInstant(targetDateTime, ZoneOffset.UTC); if (YearMonth.from(targetZonedDateTime).equals(YearMonth.from(effectiveSinceZonedDateTime))) { final ZonedDateTime startOfNextAccountingPeriod = effectiveSinceZonedDateTime .with(TemporalAdjusters.firstDayOfNextMonth()) .withHour(0) .withMinute(0) .withSecond(0) .withNano(0); final long minutesTillStartOfNextAccountingPeriod = Math.max(1, Duration .between(effectiveSinceZonedDateTime, startOfNextAccountingPeriod) .toMinutes()); final long lengthOfCurrentMonthInMinutes = 60 * 24 * effectiveSinceZonedDateTime .range(ChronoField.DAY_OF_MONTH).getMaximum(); return (long) Math.ceil((double) minutesTillStartOfNextAccountingPeriod * configuredLimit / lengthOfCurrentMonthInMinutes); } } return configuredLimit; } PrometheusBasedResourceLimitChecks(
            final WebClient webClient,
            final PrometheusBasedResourceLimitChecksConfig config,
            final AsyncCache<String, LimitedResource<Long>> connectionCountCache,
            final AsyncCache<String, LimitedResource<Duration>> connectionDurationCache,
            final AsyncCache<String, LimitedResource<Long>> dataVolumeCache);  PrometheusBasedResourceLimitChecks(
            final WebClient webClient,
            final PrometheusBasedResourceLimitChecksConfig config,
            final AsyncCache<String, LimitedResource<Long>> connectionCountCache,
            final AsyncCache<String, LimitedResource<Duration>> connectionDurationCache,
            final AsyncCache<String, LimitedResource<Long>> dataVolumeCache,
            final Tracer tracer); @Override Future<Boolean> isConnectionLimitReached(final TenantObject tenant, final SpanContext spanContext); @Override Future<Boolean> isMessageLimitReached(
            final TenantObject tenant,
            final long payloadSize,
            final SpanContext spanContext); @Override Future<Boolean> isConnectionDurationLimitReached(
            final TenantObject tenant,
            final SpanContext spanContext);  }
@Test public void verifyEffectiveResourceLimitCalculation() { final long configuredLimit = 9300; final long numberOfMinutesInSeptember = 24 * 60 * 30; final double remainingMinutesTillStartOfNextAccountingPeriod = 24 * 60 * 28 + 9 * 60 + 30; final long expectedEffectiveLimit = (long) Math.ceil(remainingMinutesTillStartOfNextAccountingPeriod * configuredLimit / numberOfMinutesInSeptember ); assertEquals(expectedEffectiveLimit, limitChecksImpl.calculateEffectiveLimit( Instant.parse("2019-09-02T14:30:00Z"), Instant.parse("2019-09-06T09:25:34Z"), ResourceLimitsPeriod.PERIOD_MODE_MONTHLY, configuredLimit)); assertEquals(configuredLimit, limitChecksImpl.calculateEffectiveLimit( Instant.parse("2019-08-06T14:30:00Z"), Instant.parse("2019-09-06T14:30:00Z"), ResourceLimitsPeriod.PERIOD_MODE_MONTHLY, configuredLimit)); assertEquals(configuredLimit, limitChecksImpl.calculateEffectiveLimit( Instant.parse("2019-08-20T07:18:23Z"), Instant.parse("2019-09-06T14:30:00Z"), ResourceLimitsPeriod.PERIOD_MODE_DAYS, configuredLimit)); assertEquals(configuredLimit, limitChecksImpl.calculateEffectiveLimit( Instant.parse("2019-06-15T14:30:00Z"), Instant.parse("2019-09-06T11:14:46Z"), ResourceLimitsPeriod.PERIOD_MODE_DAYS, configuredLimit)); }