Repository: svix/svix-webhooks (language: rust)

Issue:
Shared static apiClient between Svix instances
## Bug Report

<!--
Thank you for reporting an issue.

Please fill in as much of the template below as you're able.
-->

### Version

Java library: 1.24.0

### Platform

<!---
Output of `uname -a` (UNIX), or version and 32 or 64-bit (Windows)
-->
Darwin Mustafa-MacBook-Pro.local 24.2.0 Darwin Kernel Version 24.2.0: Fri Dec  6 19:01:59 PST 2024; root:xnu-11215.61.5~2/RELEASE_ARM64_T6000 arm64

### Description

##### Problem definiton: 
Starting from 2024-10-08, we're getting error `com.svix.exceptions.ApiException: Application not found (not_found)` 1-2 per day. Svix library retries 5 times automatically and all fails. Then, when our code retries again immediately,  it succeeds.

##### Here's the findings:
We build Svix instance with separate tokens for two different Svix endpoints. And each time when publishing a message a new Svix instance is created. In constructor, there’s a static assignment: Configuration.setDefaultApiClient(apiClient);

```
public Svix(final String token, final SvixOptions options) {
    ApiClient apiClient = new ApiClient();

    String[] tokenParts = token.split("\\.");
    String region = tokenParts[tokenParts.length - 1];
    if (region.equals("us")) {
       apiClient.setBasePath("https://api.us.svix.com/");
    } else if (region.equals("eu")) {
       apiClient.setBasePath("https://api.eu.svix.com/");
    } else if (region.equals("in")) {
       apiClient.setBasePath("https://api.in.svix.com/");
    } else {
       apiClient.setBasePath(options.getServerUrl());
    }

    apiClient.setUserAgent(String.format("svix-libs/%s/java", Svix.VERSION));

    HttpBearerAuth httpBearer = (HttpBearerAuth) apiClient.getAuthentication("HTTPBearer");
    httpBearer.setBearerToken(token);

    Configuration.setDefaultApiClient(apiClient);

    application = new Application();
    authentication = new Authentication();
    endpoint = new Endpoint();
    eventType = new EventType();
    integration = new Integration();
    message = new Message();
    messageAttempt = new MessageAttempt();
    statistics = new Statistics();
}
```

This api client is being used in MessageApi constructor:
```
public MessageApi() {
    this(Configuration.getDefaultApiClient());
} 
```
When processing messages in parallel, it’s possible that message api takes wrong apiClient because it’s set to a different one by other threads.
That’s why, fixed it by creating svix instances at startup and use those when sending messages.

Is it intended to set and share default apiClient between Svix instances?



Discussion / hints:
Thanks! I've asked @svix-jplatte to take a look.

I assume the Kotlin client is similarly affected.

Fix patch:
diff --git a/ChangeLog.md b/ChangeLog.md
index f868b5e5d..fee3ba5a4 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,5 +1,9 @@
 # Changelog
 
+## Unreleased
+* Libs/Java: Stop sharing one `ApiClient` between all `Svix` instances. Fixes a bug where multiple
+  independently instantiated `Svix` instances would always use the same base path and auth token.
+
 ## Version 1.45.0
 * CLI **(New)**: New Rust-based CLI with support for all recent Svix functionality.
 * Libs/Rust **(Breaking)**: Add `api::MessageAttemptListAttemptedMessagesOptions` and use it for
diff --git a/java/lib/src/main/java/com/svix/Application.java b/java/lib/src/main/java/com/svix/Application.java
index 2fe5a8a4e..85bb08be8 100644
--- a/java/lib/src/main/java/com/svix/Application.java
+++ b/java/lib/src/main/java/com/svix/Application.java
@@ -1,6 +1,7 @@
 package com.svix;
 
 import com.svix.exceptions.ApiException;
+import com.svix.internal.ApiClient;
 import com.svix.internal.api.ApplicationApi;
 import com.svix.models.ApplicationIn;
 import com.svix.models.ApplicationOut;
@@ -10,8 +11,8 @@
 public final class Application {
 	private final ApplicationApi api;
 
-	Application() {
-		api = new ApplicationApi();
+	Application(ApiClient apiClient) {
+		api = new ApplicationApi(apiClient);
 	}
 
 	public ListResponseApplicationOut list(final ApplicationListOptions options) throws ApiException {
diff --git a/java/lib/src/main/java/com/svix/Authentication.java b/java/lib/src/main/java/com/svix/Authentication.java
index d9b17b065..d88376bf1 100644
--- a/java/lib/src/main/java/com/svix/Authentication.java
+++ b/java/lib/src/main/java/com/svix/Authentication.java
@@ -1,6 +1,7 @@
 package com.svix;
 
 import com.svix.exceptions.ApiException;
+import com.svix.internal.ApiClient;
 import com.svix.internal.api.AuthenticationApi;
 import com.svix.models.AppPortalAccessIn;
 import com.svix.models.AppPortalAccessOut;
@@ -9,8 +10,8 @@
 public final class Authentication {
 	private final AuthenticationApi api;
 
-	Authentication() {
-		api = new AuthenticationApi();
+	Authentication(ApiClient apiClient) {
+		api = new AuthenticationApi(apiClient);
 	}
 
 	public AppPortalAccessOut appPortalAccess(final String appId, final AppPortalAccessIn appPortalAccessIn) throws ApiException {
diff --git a/java/lib/src/main/java/com/svix/BackgroundTask.java b/java/lib/src/main/java/com/svix/BackgroundTask.java
index e2cef152a..96bef1d58 100644
--- a/java/lib/src/main/java/com/svix/BackgroundTask.java
+++ b/java/lib/src/main/java/com/svix/BackgroundTask.java
@@ -1,6 +1,7 @@
 package com.svix;
 
 import com.svix.exceptions.ApiException;
+import com.svix.internal.ApiClient;
 import com.svix.internal.api.BackgroundTasksApi;
 import com.svix.models.BackgroundTaskOut;
 import com.svix.models.ListResponseBackgroundTaskOut;
@@ -8,8 +9,8 @@
 public final class BackgroundTask {
     private final BackgroundTasksApi api;
 
-    BackgroundTask() {
-        api = new BackgroundTasksApi();
+    BackgroundTask(ApiClient apiClient) {
+        api = new BackgroundTasksApi(apiClient);
     }
 
     public ListResponseBackgroundTaskOut list(final BackgroundTaskListOptions options) throws ApiException {
diff --git a/java/lib/src/main/java/com/svix/Endpoint.java b/java/lib/src/main/java/com/svix/Endpoint.java
index 34dfedd97..19b5ad9bf 100644
--- a/java/lib/src/main/java/com/svix/Endpoint.java
+++ b/java/lib/src/main/java/com/svix/Endpoint.java
@@ -1,6 +1,7 @@
 package com.svix;
 
 import com.svix.exceptions.ApiException;
+import com.svix.internal.ApiClient;
 import com.svix.internal.api.EndpointApi;
 import com.svix.models.EndpointHeadersIn;
 import com.svix.models.EndpointHeadersOut;
@@ -23,8 +24,8 @@
 public final class Endpoint {
 	private final EndpointApi api;
 
-	public Endpoint() {
-		api = new EndpointApi();
+	public Endpoint(ApiClient apiClient) {
+		api = new EndpointApi(apiClient);
 	}
 
 	public ListResponseEndpointOut list(final String appId, final EndpointListOptions options) throws ApiException {
diff --git a/java/lib/src/main/java/com/svix/EventType.java b/java/lib/src/main/java/com/svix/EventType.java
index 677f8c17d..18517291d 100644
--- a/java/lib/src/main/java/com/svix/EventType.java
+++ b/java/lib/src/main/java/com/svix/EventType.java
@@ -1,6 +1,7 @@
 package com.svix;
 
 import com.svix.exceptions.ApiException;
+import com.svix.internal.ApiClient;
 import com.svix.internal.api.EventTypeApi;
 import com.svix.models.EventTypeImportOpenApiIn;
 import com.svix.models.EventTypeImportOpenApiOut;
@@ -13,8 +14,8 @@
 public final class EventType {
 	private final EventTypeApi api;
 
-	public EventType() {
-		api = new EventTypeApi();
+	public EventType(ApiClient apiClient) {
+		api = new EventTypeApi(apiClient);
 	}
 
 	public ListResponseEventTypeOut list(final EventTypeListOptions options) throws ApiException {
diff --git a/java/lib/src/main/java/com/svix/Integration.java b/java/lib/src/main/java/com/svix/Integration.java
index 8d1cfd613..2f1ee62ba 100644
--- a/java/lib/src/main/java/com/svix/Integration.java
+++ b/java/lib/src/main/java/com/svix/Integration.java
@@ -1,6 +1,7 @@
 package com.svix;
 
 import com.svix.exceptions.ApiException;
+import com.svix.internal.ApiClient;
 import com.svix.internal.api.IntegrationApi;
 import com.svix.models.IntegrationIn;
 import com.svix.models.IntegrationOut;
@@ -11,8 +12,8 @@
 public final class Integration {
 	private final IntegrationApi api;
 
-	public Integration() {
-		api = new IntegrationApi();
+	public Integration(ApiClient apiClient) {
+		api = new IntegrationApi(apiClient);
 	}
 
 	public ListResponseIntegrationOut list(final String appId, final IntegrationListOptions options) throws ApiException {
diff --git a/java/lib/src/main/java/com/svix/Message.java b/java/lib/src/main/java/com/svix/Message.java
index 72343d4c7..4ea90b775 100644
--- a/java/lib/src/main/java/com/svix/Message.java
+++ b/java/lib/src/main/java/com/svix/Message.java
@@ -6,6 +6,7 @@
 import java.util.Map;
 
 import com.svix.exceptions.ApiException;
+import com.svix.internal.ApiClient;
 import com.svix.internal.api.MessageApi;
 import com.svix.models.ListResponseMessageOut;
 import com.svix.models.MessageIn;
@@ -15,8 +16,8 @@
 public final class Message {
 	private final MessageApi api;
 
-	Message() {
-		api = new MessageApi();
+	Message(ApiClient apiClient) {
+		api = new MessageApi(apiClient);
 	}
 
 	private static MessageIn messageInEmptyPayload() {
diff --git a/java/lib/src/main/java/com/svix/MessageAttempt.java b/java/lib/src/main/java/com/svix/MessageAttempt.java
index a80cc8cbd..b46a9050a 100644
--- a/java/lib/src/main/java/com/svix/MessageAttempt.java
+++ b/java/lib/src/main/java/com/svix/MessageAttempt.java
@@ -3,6 +3,7 @@
 import java.util.HashSet;
 
 import com.svix.exceptions.ApiException;
+import com.svix.internal.ApiClient;
 import com.svix.internal.api.MessageAttemptApi;
 import com.svix.models.ListResponseEndpointMessageOut;
 import com.svix.models.ListResponseMessageAttemptEndpointOut;
@@ -13,8 +14,8 @@
 public final class MessageAttempt {
 	private final MessageAttemptApi api;
 
-	MessageAttempt() {
-		api = new MessageAttemptApi();
+	MessageAttempt(ApiClient apiClient) {
+		api = new MessageAttemptApi(apiClient);
 	}
 
 	/*
diff --git a/java/lib/src/main/java/com/svix/OperationalWebhookEndpoint.java b/java/lib/src/main/java/com/svix/OperationalWebhookEndpoint.java
index 7d8797fcb..eb568caf0 100644
--- a/java/lib/src/main/java/com/svix/OperationalWebhookEndpoint.java
+++ b/java/lib/src/main/java/com/svix/OperationalWebhookEndpoint.java
@@ -1,6 +1,7 @@
 package com.svix;
 
 import com.svix.exceptions.ApiException;
+import com.svix.internal.ApiClient;
 import com.svix.internal.api.WebhookEndpointApi;
 import com.svix.models.OperationalWebhookEndpointIn;
 import com.svix.models.OperationalWebhookEndpointOut;
@@ -12,8 +13,8 @@
 public final class OperationalWebhookEndpoint {
 	private final WebhookEndpointApi api;
 
-	public OperationalWebhookEndpoint() {
-		api = new WebhookEndpointApi();
+	public OperationalWebhookEndpoint(ApiClient apiClient) {
+		api = new WebhookEndpointApi(apiClient);
 	}
 
 	public ListResponseOperationalWebhookEndpointOut list(final OperationalWebhookEndpointListOptions options) throws ApiException {
diff --git a/java/lib/src/main/java/com/svix/Statistics.java b/java/lib/src/main/java/com/svix/Statistics.java
index 021ba9fe7..a6eece4d6 100644
--- a/java/lib/src/main/java/com/svix/Statistics.java
+++ b/java/lib/src/main/java/com/svix/Statistics.java
@@ -1,6 +1,7 @@
 package com.svix;
 
 import com.svix.exceptions.ApiException;
+import com.svix.internal.ApiClient;
 import com.svix.internal.api.StatisticsApi;
 import com.svix.models.AggregateEventTypesOut;
 import com.svix.models.AppUsageStatsIn;
@@ -9,8 +10,8 @@
 public class Statistics {
     private final StatisticsApi api;
 
-    Statistics() {
-        api = new StatisticsApi();
+    Statistics(ApiClient apiClient) {
+        api = new StatisticsApi(apiClient);
     }
 
     public AppUsageStatsOut aggregateAppStats(final AppUsageStatsIn appUsageStatsIn, final PostOptions options) throws ApiException {
diff --git a/java/lib/src/main/java/com/svix/Svix.java b/java/lib/src/main/java/com/svix/Svix.java
index 81ca3e742..db1dcc2a0 100644
--- a/java/lib/src/main/java/com/svix/Svix.java
+++ b/java/lib/src/main/java/com/svix/Svix.java
@@ -40,23 +40,20 @@ public Svix(final String token, final SvixOptions options) {
 			}
 		}
 
-
 		apiClient.setUserAgent(String.format("svix-libs/%s/java", Svix.VERSION));
 
 		HttpBearerAuth httpBearer = (HttpBearerAuth) apiClient.getAuthentication("HTTPBearer");
 		httpBearer.setBearerToken(token);
 
-		Configuration.setDefaultApiClient(apiClient);
-
-		application = new Application();
-		authentication = new Authentication();
-		endpoint = new Endpoint();
-		eventType = new EventType();
-		integration = new Integration();
-		message = new Message();
-		messageAttempt = new MessageAttempt();
-		statistics = new Statistics();
-		operationalWebhookEndpoint = new OperationalWebhookEndpoint();
+		application = new Application(apiClient);
+		authentication = new Authentication(apiClient);
+		endpoint = new Endpoint(apiClient);
+		eventType = new EventType(apiClient);
+		integration = new Integration(apiClient);
+		message = new Message(apiClient);
+		messageAttempt = new MessageAttempt(apiClient);
+		statistics = new Statistics(apiClient);
+		operationalWebhookEndpoint = new OperationalWebhookEndpoint(apiClient);
 	}
 
 	public Application getApplication() {


Test patch: