Add event queue and HTTP retry
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/PatchSetReviewer.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/PatchSetReviewer.java
index 2dc7ed2..c640b7e 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/PatchSetReviewer.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/PatchSetReviewer.java
@@ -1,13 +1,11 @@
package com.googlesource.gerrit.plugins.chatgpt;
-import com.google.gerrit.server.project.NoSuchProjectException;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import com.googlesource.gerrit.plugins.chatgpt.client.GerritClient;
import com.googlesource.gerrit.plugins.chatgpt.client.OpenAiClient;
import lombok.extern.slf4j.Slf4j;
-import java.io.IOException;
import java.util.*;
import java.util.stream.Collectors;
@@ -25,7 +23,7 @@
this.openAiClient = openAiClient;
}
- public void review(Configuration config, String fullChangeId) throws IOException, InterruptedException, NoSuchProjectException {
+ public void review(Configuration config, String fullChangeId) throws Exception {
String patchSet = gerritClient.getPatchSet(config, fullChangeId);
if (config.isPatchSetReduction()) {
patchSet = reducePatchSet(patchSet);
@@ -72,8 +70,7 @@
.collect(Collectors.joining("\n"));
}
- private String getReviewSuggestion(Configuration config, String changeId, String patchSet)
- throws IOException, InterruptedException {
+ private String getReviewSuggestion(Configuration config, String changeId, String patchSet) throws Exception {
List<String> patchLines = Arrays.asList(patchSet.split("\n"));
if (patchLines.size() > config.getMaxReviewLines()) {
log.warn("Patch set too large. Skipping review. changeId: {}", changeId);
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/GerritClient.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/GerritClient.java
index df0cecf..c5d1430 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/GerritClient.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/GerritClient.java
@@ -9,11 +9,9 @@
import java.io.IOException;
import java.net.URI;
-import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.nio.charset.StandardCharsets;
-import java.time.Duration;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
@@ -23,14 +21,10 @@
@Slf4j
@Singleton
public class GerritClient {
-
private final Gson gson = new Gson();
+ private final HttpClientWithRetry httpClientWithRetry = new HttpClientWithRetry();
- private final HttpClient httpClient = HttpClient.newBuilder()
- .connectTimeout(Duration.ofMinutes(5))
- .build();
-
- public String getPatchSet(Configuration config, String fullChangeId) throws IOException, InterruptedException {
+ public String getPatchSet(Configuration config, String fullChangeId) throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.header(HttpHeaders.AUTHORIZATION, generateBasicAuth(config.getGerritUserName(),
config.getGerritPassword()))
@@ -38,7 +32,8 @@
+ UriResourceLocator.gerritPatchSetUri(fullChangeId)))
.build();
- HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
+ //HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
+ HttpResponse<String> response = httpClientWithRetry.execute(request);
if (response.statusCode() != HTTP_OK) {
log.error("Failed to get patch. Response: {}", response);
@@ -55,7 +50,7 @@
return "Basic " + Base64.getEncoder().encodeToString(auth.getBytes(StandardCharsets.UTF_8));
}
- public void postComment(Configuration config, String fullChangeId, String message) throws IOException, InterruptedException {
+ public void postComment(Configuration config, String fullChangeId, String message) throws Exception {
Map<String, String> map = new HashMap<>();
map.put("message", message);
String json = gson.toJson(map);
@@ -69,7 +64,8 @@
.POST(HttpRequest.BodyPublishers.ofString(json))
.build();
- HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
+ //HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
+ HttpResponse<String> response = httpClientWithRetry.execute(request);
if (response.statusCode() != HTTP_OK) {
log.error("Review post failed with status code: {}", response.statusCode());
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/HttpClientWithRetry.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/HttpClientWithRetry.java
new file mode 100644
index 0000000..5e9ec56
--- /dev/null
+++ b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/HttpClientWithRetry.java
@@ -0,0 +1,37 @@
+package com.googlesource.gerrit.plugins.chatgpt.client;
+
+import com.github.rholder.retry.*;
+import com.google.inject.Singleton;
+
+import java.net.http.HttpClient;
+import java.net.http.HttpRequest;
+import java.net.http.HttpResponse;
+import java.time.Duration;
+import java.util.concurrent.ExecutionException;
+import java.util.concurrent.TimeUnit;
+
+import static java.net.HttpURLConnection.HTTP_OK;
+
+@Singleton
+public class HttpClientWithRetry {
+ private final Retryer<HttpResponse<String>> retryer;
+
+ private final HttpClient httpClient = HttpClient.newBuilder()
+ .connectTimeout(Duration.ofMinutes(5))
+ .build();
+
+ public HttpClientWithRetry() {
+ this.retryer = RetryerBuilder.<HttpResponse<String>>newBuilder()
+ .retryIfException()
+ .retryIfResult(response -> response.statusCode() != HTTP_OK)
+ .withWaitStrategy(WaitStrategies.fixedWait(10, TimeUnit.SECONDS))
+ .withStopStrategy(StopStrategies.stopAfterAttempt(3))
+ .build();
+ }
+
+ public HttpResponse<String> execute(HttpRequest request) throws ExecutionException, RetryException {
+ return retryer.call(() -> httpClient.send(request, HttpResponse.BodyHandlers.ofString()));
+ }
+
+}
+
diff --git a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/OpenAiClient.java b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/OpenAiClient.java
index a591ba4..f595d89 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/OpenAiClient.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/chatgpt/client/OpenAiClient.java
@@ -11,31 +11,22 @@
import java.io.IOException;
import java.io.StringReader;
import java.net.URI;
-import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
-import java.time.Duration;
import java.util.List;
import java.util.Optional;
-import static java.net.HttpURLConnection.HTTP_OK;
-
@Slf4j
@Singleton
public class OpenAiClient {
private final Gson gson = new Gson();
+ private final HttpClientWithRetry httpClientWithRetry = new HttpClientWithRetry();
- private final HttpClient httpClient = HttpClient.newBuilder()
- .connectTimeout(Duration.ofMinutes(5))
- .build();
-
- public String ask(Configuration config, String patchSet) throws IOException, InterruptedException {
+ public String ask(Configuration config, String patchSet) throws Exception {
HttpRequest request = createRequest(config, patchSet);
- HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());
- if (response.statusCode() != HTTP_OK) {
- throw new IOException("Unexpected response " + response);
- }
+ HttpResponse<String> response = httpClientWithRetry.execute(request);
+
String body = response.body();
if (body == null) {
throw new IOException("responseBody is null");
@@ -53,13 +44,13 @@
}
private HttpRequest createRequest(Configuration config, String patchSet) {
- String jsonRequest = createRequestBody(config, patchSet);
+ String requestBody = createRequestBody(config, patchSet);
return HttpRequest.newBuilder()
.header(HttpHeaders.AUTHORIZATION, "Bearer " + config.getGptToken())
.header(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString())
.uri(URI.create(URI.create(config.getGptDomain()) + UriResourceLocator.chatCompletionsUri()))
- .POST(HttpRequest.BodyPublishers.ofString(jsonRequest))
+ .POST(HttpRequest.BodyPublishers.ofString(requestBody))
.build();
}
diff --git a/src/test/java/com/googlesource/gerrit/plugins/chatgpt/integration/CodeReviewPluginIT.java b/src/test/java/com/googlesource/gerrit/plugins/chatgpt/integration/CodeReviewPluginIT.java
index 1b2c204..c6a1d63 100644
--- a/src/test/java/com/googlesource/gerrit/plugins/chatgpt/integration/CodeReviewPluginIT.java
+++ b/src/test/java/com/googlesource/gerrit/plugins/chatgpt/integration/CodeReviewPluginIT.java
@@ -11,8 +11,6 @@
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnitRunner;
-import java.io.IOException;
-
import static junit.framework.TestCase.assertNotNull;
import static org.mockito.Mockito.when;
@@ -31,7 +29,7 @@
private OpenAiClient openAiClient;
@Test
- public void sayHelloToGPT() throws IOException, InterruptedException {
+ public void sayHelloToGPT() throws Exception {
when(config.getGptDomain()).thenReturn(Configuration.OPENAI_DOMAIN);
when(config.getGptToken()).thenReturn("Your GPT token");
when(config.getGptModel()).thenReturn(Configuration.DEFAULT_GPT_MODEL);
@@ -43,7 +41,7 @@
}
@Test
- public void getPatchSet() throws IOException, InterruptedException {
+ public void getPatchSet() throws Exception {
when(config.getGerritAuthBaseUrl()).thenReturn("Your Gerrit URL");
when(config.getGerritUserName()).thenReturn("Your Gerrit username");
when(config.getGerritPassword()).thenReturn("Your Gerrit password");
@@ -54,7 +52,7 @@
}
@Test
- public void postComment() throws IOException, InterruptedException {
+ public void postComment() throws Exception {
when(config.getGerritAuthBaseUrl()).thenReturn("Your Gerrit URL");
when(config.getGerritUserName()).thenReturn("Your Gerrit username");
when(config.getGerritPassword()).thenReturn("Your Gerrit password");