11package io .apitally .common ;
22
3+ import io .apitally .common .dto .Path ;
4+ import io .apitally .common .dto .StartupData ;
5+ import io .apitally .common .dto .SyncData ;
36import java .io .InputStream ;
47import java .net .URI ;
58import java .net .http .HttpClient ;
1720import java .util .concurrent .ScheduledExecutorService ;
1821import java .util .concurrent .ScheduledFuture ;
1922import java .util .concurrent .TimeUnit ;
20-
2123import org .slf4j .Logger ;
2224import org .slf4j .LoggerFactory ;
2325import org .springframework .retry .support .RetryTemplate ;
2426
25- import io .apitally .common .dto .Path ;
26- import io .apitally .common .dto .StartupData ;
27- import io .apitally .common .dto .SyncData ;
28-
2927public class ApitallyClient {
3028 public static class RetryableHubRequestException extends Exception {
3129 public RetryableHubRequestException (String message ) {
@@ -46,16 +44,18 @@ public enum HubRequestStatus {
4644 private static final int INITIAL_PERIOD_SECONDS = 3600 ;
4745 private static final int MAX_QUEUE_TIME_SECONDS = 3600 ;
4846 private static final int REQUEST_TIMEOUT_SECONDS = 10 ;
49- private static final String HUB_BASE_URL = Optional .ofNullable (System .getenv ("APITALLY_HUB_BASE_URL" ))
50- .filter (s -> !s .trim ().isEmpty ())
51- .orElse ("https://hub.apitally.io" );
47+ private static final String HUB_BASE_URL =
48+ Optional .ofNullable (System .getenv ("APITALLY_HUB_BASE_URL" ))
49+ .filter (s -> !s .trim ().isEmpty ())
50+ .orElse ("https://hub.apitally.io" );
5251
5352 private static final Logger logger = LoggerFactory .getLogger (ApitallyClient .class );
54- private static final RetryTemplate retryTemplate = RetryTemplate .builder ()
55- .maxAttempts (3 )
56- .exponentialBackoff (Duration .ofSeconds (1 ), 2 , Duration .ofSeconds (4 ), true )
57- .retryOn (RetryableHubRequestException .class )
58- .build ();
53+ private static final RetryTemplate retryTemplate =
54+ RetryTemplate .builder ()
55+ .maxAttempts (3 )
56+ .exponentialBackoff (Duration .ofSeconds (1 ), 2 , Duration .ofSeconds (4 ), true )
57+ .retryOn (RetryableHubRequestException .class )
58+ .build ();
5959
6060 private final String clientId ;
6161 private final String env ;
@@ -121,31 +121,35 @@ private void sendStartupData() {
121121 if (startupData == null ) {
122122 return ;
123123 }
124- HttpRequest request = HttpRequest .newBuilder ()
125- .uri (getHubUrl ("startup" ))
126- .header ("Content-Type" , "application/json" )
127- .POST (HttpRequest .BodyPublishers .ofString (startupData .toJSON ()))
128- .build ();
129- sendHubRequest (request ).thenAccept (status -> {
130- if (status == HubRequestStatus .OK ) {
131- startupDataSent = true ;
132- startupData = null ;
133- } else if (status == HubRequestStatus .VALIDATION_ERROR ) {
134- startupDataSent = false ;
135- startupData = null ;
136- } else {
137- startupDataSent = false ;
138- }
139- });
124+ HttpRequest request =
125+ HttpRequest .newBuilder ()
126+ .uri (getHubUrl ("startup" ))
127+ .header ("Content-Type" , "application/json" )
128+ .POST (HttpRequest .BodyPublishers .ofString (startupData .toJSON ()))
129+ .build ();
130+ sendHubRequest (request )
131+ .thenAccept (
132+ status -> {
133+ if (status == HubRequestStatus .OK ) {
134+ startupDataSent = true ;
135+ startupData = null ;
136+ } else if (status == HubRequestStatus .VALIDATION_ERROR ) {
137+ startupDataSent = false ;
138+ startupData = null ;
139+ } else {
140+ startupDataSent = false ;
141+ }
142+ });
140143 }
141144
142145 private void sendSyncData () {
143- SyncData data = new SyncData (
144- instanceLock .getInstanceUuid (),
145- requestCounter .getAndResetRequests (),
146- validationErrorCounter .getAndResetValidationErrors (),
147- serverErrorCounter .getAndResetServerErrors (),
148- consumerRegistry .getAndResetConsumers ());
146+ SyncData data =
147+ new SyncData (
148+ instanceLock .getInstanceUuid (),
149+ requestCounter .getAndResetRequests (),
150+ validationErrorCounter .getAndResetValidationErrors (),
151+ serverErrorCounter .getAndResetServerErrors (),
152+ consumerRegistry .getAndResetConsumers ());
149153 syncDataQueue .offer (data );
150154
151155 int i = 0 ;
@@ -158,11 +162,12 @@ private void sendSyncData() {
158162 // Add random delay between retries
159163 Thread .sleep (100 + random .nextInt (400 ));
160164 }
161- HttpRequest request = HttpRequest .newBuilder ()
162- .uri (getHubUrl ("sync" ))
163- .header ("Content-Type" , "application/json" )
164- .POST (HttpRequest .BodyPublishers .ofString (payload .toJSON ()))
165- .build ();
165+ HttpRequest request =
166+ HttpRequest .newBuilder ()
167+ .uri (getHubUrl ("sync" ))
168+ .header ("Content-Type" , "application/json" )
169+ .POST (HttpRequest .BodyPublishers .ofString (payload .toJSON ()))
170+ .build ();
166171 HubRequestStatus status = sendHubRequest (request ).join ();
167172 if (status == HubRequestStatus .RETRYABLE_ERROR ) {
168173 syncDataQueue .offer (payload );
@@ -191,11 +196,12 @@ private void sendLogData() {
191196 }
192197 }
193198 try (InputStream inputStream = logFile .getInputStream ()) {
194- HttpRequest request = HttpRequest .newBuilder ()
195- .uri (getHubUrl ("log" , "uuid=" + logFile .getUuid ().toString ()))
196- .header ("Content-Type" , "application/octet-stream" )
197- .POST (HttpRequest .BodyPublishers .ofInputStream (() -> inputStream ))
198- .build ();
199+ HttpRequest request =
200+ HttpRequest .newBuilder ()
201+ .uri (getHubUrl ("log" , "uuid=" + logFile .getUuid ().toString ()))
202+ .header ("Content-Type" , "application/octet-stream" )
203+ .POST (HttpRequest .BodyPublishers .ofInputStream (() -> inputStream ))
204+ .build ();
199205 HubRequestStatus status = sendHubRequest (request ).join ();
200206 if (status == HubRequestStatus .PAYMENT_REQUIRED ) {
201207 requestLogger .clear ();
@@ -217,70 +223,87 @@ private void sendLogData() {
217223 }
218224
219225 public CompletableFuture <HubRequestStatus > sendHubRequest (HttpRequest request ) {
220- return CompletableFuture .supplyAsync (() -> {
221- try {
222- return retryTemplate .execute (context -> {
226+ return CompletableFuture .supplyAsync (
227+ () -> {
223228 try {
224- logger .debug ("Sending request to Apitally hub: {}" , request .uri ());
225- HttpResponse <String > response = httpClient .send (request , HttpResponse .BodyHandlers .ofString ());
226- if (response .statusCode () >= 200 && response .statusCode () < 300 ) {
227- return HubRequestStatus .OK ;
228- } else if (response .statusCode () == 402 ) {
229- return HubRequestStatus .PAYMENT_REQUIRED ;
230- } else if (response .statusCode () == 404 ) {
231- enabled = false ;
232- stopSync ();
233- requestLogger .close ();
234- logger .error ("Invalid Apitally client ID: {}" , clientId );
235- return HubRequestStatus .INVALID_CLIENT_ID ;
236- } else if (response .statusCode () == 422 ) {
237- logger .error ("Received validation error from Apitally hub: {}" , response .body ());
238- return HubRequestStatus .VALIDATION_ERROR ;
239- } else {
240- throw new RetryableHubRequestException (
241- "Hub request failed with status code " + response .statusCode ());
242- }
229+ return retryTemplate .execute (
230+ context -> {
231+ try {
232+ logger .debug (
233+ "Sending request to Apitally hub: {}" ,
234+ request .uri ());
235+ HttpResponse <String > response =
236+ httpClient .send (
237+ request ,
238+ HttpResponse .BodyHandlers .ofString ());
239+ if (response .statusCode () >= 200
240+ && response .statusCode () < 300 ) {
241+ return HubRequestStatus .OK ;
242+ } else if (response .statusCode () == 402 ) {
243+ return HubRequestStatus .PAYMENT_REQUIRED ;
244+ } else if (response .statusCode () == 404 ) {
245+ enabled = false ;
246+ stopSync ();
247+ requestLogger .close ();
248+ logger .error (
249+ "Invalid Apitally client ID: {}" , clientId );
250+ return HubRequestStatus .INVALID_CLIENT_ID ;
251+ } else if (response .statusCode () == 422 ) {
252+ logger .error (
253+ "Received validation error from Apitally hub: {}" ,
254+ response .body ());
255+ return HubRequestStatus .VALIDATION_ERROR ;
256+ } else {
257+ throw new RetryableHubRequestException (
258+ "Hub request failed with status code "
259+ + response .statusCode ());
260+ }
261+ } catch (Exception e ) {
262+ throw new RetryableHubRequestException (
263+ "Hub request failed with exception: "
264+ + e .getMessage ());
265+ }
266+ });
243267 } catch (Exception e ) {
244- throw new RetryableHubRequestException (
245- "Hub request failed with exception: " + e . getMessage ()) ;
268+ logger . error ( "Error sending request to Apitally hub" , e );
269+ return HubRequestStatus . RETRYABLE_ERROR ;
246270 }
247271 });
248- } catch (Exception e ) {
249- logger .error ("Error sending request to Apitally hub" , e );
250- return HubRequestStatus .RETRYABLE_ERROR ;
251- }
252- });
253272 }
254273
255274 public void startSync () {
256275 if (scheduler == null ) {
257- scheduler = Executors .newSingleThreadScheduledExecutor (r -> {
258- Thread thread = new Thread (r , "apitally-sync" );
259- thread .setDaemon (true );
260- return thread ;
261- });
276+ scheduler =
277+ Executors .newSingleThreadScheduledExecutor (
278+ r -> {
279+ Thread thread = new Thread (r , "apitally-sync" );
280+ thread .setDaemon (true );
281+ return thread ;
282+ });
262283 }
263284
264285 if (syncTask != null ) {
265286 syncTask .cancel (false );
266287 }
267288
268289 // Start with shorter initial sync interval
269- syncTask = scheduler .scheduleAtFixedRate (
270- this ::sync ,
271- 0 ,
272- INITIAL_SYNC_INTERVAL_SECONDS ,
273- TimeUnit .SECONDS );
290+ syncTask =
291+ scheduler .scheduleAtFixedRate (
292+ this ::sync , 0 , INITIAL_SYNC_INTERVAL_SECONDS , TimeUnit .SECONDS );
274293
275294 // Schedule a one-time task to switch to regular sync interval
276- scheduler .schedule (() -> {
277- syncTask .cancel (false );
278- syncTask = scheduler .scheduleAtFixedRate (
279- this ::sync ,
280- SYNC_INTERVAL_SECONDS ,
281- SYNC_INTERVAL_SECONDS ,
282- TimeUnit .SECONDS );
283- }, INITIAL_PERIOD_SECONDS , TimeUnit .SECONDS );
295+ scheduler .schedule (
296+ () -> {
297+ syncTask .cancel (false );
298+ syncTask =
299+ scheduler .scheduleAtFixedRate (
300+ this ::sync ,
301+ SYNC_INTERVAL_SECONDS ,
302+ SYNC_INTERVAL_SECONDS ,
303+ TimeUnit .SECONDS );
304+ },
305+ INITIAL_PERIOD_SECONDS ,
306+ TimeUnit .SECONDS );
284307 }
285308
286309 public void stopSync () {
0 commit comments