diff --git a/backend/src/main/java/org/cryptomator/hub/license/LicenseHolder.java b/backend/src/main/java/org/cryptomator/hub/license/LicenseHolder.java index 060c8b30..71ea3cb6 100644 --- a/backend/src/main/java/org/cryptomator/hub/license/LicenseHolder.java +++ b/backend/src/main/java/org/cryptomator/hub/license/LicenseHolder.java @@ -43,6 +43,9 @@ public class LicenseHolder { @Inject LicenseValidator licenseValidator; + @Inject + RandomMinuteSleeper randomMinuteSleeper; + private static final Logger LOG = Logger.getLogger(LicenseHolder.class); private DecodedJWT license; @@ -106,6 +109,7 @@ public void set(String token) throws JWTVerificationException { @Scheduled(cron = "0 0 1 * * ?", timeZone = "UTC", concurrentExecution = Scheduled.ConcurrentExecution.SKIP) void refreshLicenseScheduler() throws InterruptedException { if (license != null) { + randomMinuteSleeper.sleep(); var refreshUrl = licenseValidator.refreshUrl(license.getToken()); if (refreshUrl.isPresent()) { var client = HttpClient.newBuilder().followRedirects(HttpClient.Redirect.NORMAL).build(); diff --git a/backend/src/main/java/org/cryptomator/hub/license/RandomMinuteSleeper.java b/backend/src/main/java/org/cryptomator/hub/license/RandomMinuteSleeper.java new file mode 100644 index 00000000..b5789c9d --- /dev/null +++ b/backend/src/main/java/org/cryptomator/hub/license/RandomMinuteSleeper.java @@ -0,0 +1,16 @@ +package org.cryptomator.hub.license; + +import jakarta.enterprise.context.ApplicationScoped; + +import java.util.Random; + +@ApplicationScoped +public class RandomMinuteSleeper { + + private static final long MINUTE_IN_MILLIS = 60 * 1000L; + + void sleep() throws InterruptedException { + Thread.sleep(new Random().nextInt(0, 60) * MINUTE_IN_MILLIS); + } + +} diff --git a/backend/src/test/java/org/cryptomator/hub/license/LicenseHolderTest.java b/backend/src/test/java/org/cryptomator/hub/license/LicenseHolderTest.java index e7ab7d4d..b7487bd1 100644 --- a/backend/src/test/java/org/cryptomator/hub/license/LicenseHolderTest.java +++ b/backend/src/test/java/org/cryptomator/hub/license/LicenseHolderTest.java @@ -51,14 +51,18 @@ class TestPostConstruct { @InjectMock LicenseValidator validator; + @InjectMock + RandomMinuteSleeper randomMinuteSleeper; + MockedStatic settingsClass; @BeforeEach - public void setup() { + public void setup() throws InterruptedException { Query mockQuery = Mockito.mock(Query.class); Mockito.doNothing().when(session).persist(Mockito.any()); Mockito.when(session.createQuery(Mockito.anyString())).thenReturn(mockQuery); Mockito.when(mockQuery.getSingleResult()).thenReturn(0l); + Mockito.doNothing().when(randomMinuteSleeper).sleep(); Arc.container().instance(LicenseHolder.class).destroy(); @@ -131,14 +135,18 @@ class TestSetter { @InjectMock LicenseValidator validator; + @InjectMock + RandomMinuteSleeper randomMinuteSleeper; + MockedStatic settingsClass; @BeforeEach - public void setup() { + public void setup() throws InterruptedException { Query mockQuery = Mockito.mock(Query.class); Mockito.doNothing().when(session).persist(Mockito.any()); Mockito.when(session.createQuery(Mockito.anyString())).thenReturn(mockQuery); Mockito.when(mockQuery.getSingleResult()).thenReturn(0l); + Mockito.doNothing().when(randomMinuteSleeper).sleep(); Arc.container().instance(LicenseHolder.class).destroy(); @@ -203,14 +211,18 @@ class TestRefreshLicense { @InjectMock LicenseValidator validator; + @InjectMock + RandomMinuteSleeper randomMinuteSleeper; + MockedStatic settingsClass; @BeforeEach - public void setup() { + public void setup() throws InterruptedException { Query mockQuery = Mockito.mock(Query.class); Mockito.doNothing().when(session).persist(Mockito.any()); Mockito.when(session.createQuery(Mockito.anyString())).thenReturn(mockQuery); Mockito.when(mockQuery.getSingleResult()).thenReturn(0l); + Mockito.doNothing().when(randomMinuteSleeper).sleep(); Arc.container().instance(LicenseHolder.class).destroy(); @@ -389,6 +401,9 @@ class LicenseHolderInitPropsTest { @InjectMock LicenseValidator validator; + @InjectMock + RandomMinuteSleeper randomMinuteSleeper; + MockedStatic settingsClass; public static class ValidInitPropsInstanceTestProfile implements QuarkusTestProfile { @@ -399,11 +414,12 @@ public Map getConfigOverrides() { } @BeforeEach - public void setup() { + public void setup() throws InterruptedException { Query mockQuery = Mockito.mock(Query.class); Mockito.doNothing().when(session).persist(Mockito.any()); Mockito.when(session.createQuery(Mockito.anyString())).thenReturn(mockQuery); Mockito.when(mockQuery.getSingleResult()).thenReturn(0l); + Mockito.doNothing().when(randomMinuteSleeper).sleep(); Arc.container().instance(LicenseHolder.class).destroy();