Skip to content

Commit ff26624

Browse files
Adding exception handling
1 parent 0ea22a0 commit ff26624

File tree

2 files changed

+58
-1
lines changed

2 files changed

+58
-1
lines changed

x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/external/http/sender/HttpRequestSender.java

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,9 @@
77

88
package org.elasticsearch.xpack.inference.external.http.sender;
99

10+
import org.apache.logging.log4j.LogManager;
1011
import org.apache.logging.log4j.Logger;
12+
import org.elasticsearch.ExceptionsHelper;
1113
import org.elasticsearch.action.ActionListener;
1214
import org.elasticsearch.action.support.ContextPreservingActionListener;
1315
import org.elasticsearch.cluster.service.ClusterService;
@@ -77,6 +79,7 @@ public Sender createSender() {
7779
}
7880
}
7981

82+
private static final Logger logger = LogManager.getLogger(HttpRequestSender.class);
8083
private static final TimeValue START_COMPLETED_WAIT_TIME = TimeValue.timeValueSeconds(5);
8184

8285
private final ThreadPool threadPool;
@@ -133,8 +136,17 @@ private void startInternal(ActionListener<Void> listener) {
133136
@Override
134137
public void startSynchronously() {
135138
if (started.compareAndSet(false, true)) {
136-
startInternal(ActionListener.noop());
139+
ActionListener<Void> listener = ActionListener.wrap(
140+
unused -> {},
141+
exception -> {
142+
logger.error("Http sender failed to start", exception);
143+
ExceptionsHelper.maybeDieOnAnotherThread(exception);
144+
}
145+
);
146+
startInternal(listener);
137147
}
148+
// Handle the case where start*() was already called and this would return immediately because the started flag is already true
149+
waitForStartToComplete();
138150
}
139151

140152
private void waitForStartToComplete() {

x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/external/http/sender/HttpRequestSenderTests.java

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,7 @@
6262
import static org.mockito.ArgumentMatchers.anyString;
6363
import static org.mockito.Mockito.any;
6464
import static org.mockito.Mockito.doAnswer;
65+
import static org.mockito.Mockito.doThrow;
6566
import static org.mockito.Mockito.mock;
6667
import static org.mockito.Mockito.when;
6768

@@ -112,6 +113,50 @@ public void testCreateSender_CanCallStartMultipleTimes() throws Exception {
112113
}
113114
}
114115

116+
public void testStart_ThrowsException_WhenAnErrorOccurs() throws IOException {
117+
var mockManager = mock(HttpClientManager.class);
118+
when(mockManager.getHttpClient()).thenReturn(mock(HttpClient.class));
119+
doThrow(new Error("failed")).when(mockManager).start();
120+
121+
var senderFactory = new HttpRequestSender.Factory(
122+
ServiceComponentsTests.createWithEmptySettings(threadPool),
123+
mockManager,
124+
mockClusterServiceEmpty()
125+
);
126+
127+
try (var sender = senderFactory.createSender()) {
128+
// Checking for both exception types because there's a race condition between the Error being thrown on a separate thread
129+
// and the startCompleted latch timing out waiting for the start to complete
130+
var exception = expectThrowsAnyOf(List.of(Error.class, IllegalStateException.class), sender::startSynchronously);
131+
132+
if (exception instanceof Error) {
133+
assertThat(exception.getMessage(), is("failed"));
134+
} else {
135+
// IllegalStateException can be thrown if the startCompleted latch times out waiting for the start to complete
136+
assertThat(exception.getMessage(), is("Http sender startup did not complete in time"));
137+
}
138+
}
139+
}
140+
141+
public void testStart_ThrowsExceptionWaitingForStartToComplete() throws IOException {
142+
var mockManager = mock(HttpClientManager.class);
143+
when(mockManager.getHttpClient()).thenReturn(mock(HttpClient.class));
144+
// This won't get rethrown because it is not an Error
145+
doThrow(new IllegalArgumentException("failed")).when(mockManager).start();
146+
147+
var senderFactory = new HttpRequestSender.Factory(
148+
ServiceComponentsTests.createWithEmptySettings(threadPool),
149+
mockManager,
150+
mockClusterServiceEmpty()
151+
);
152+
153+
try (var sender = senderFactory.createSender()) {
154+
var exception = expectThrows(IllegalStateException.class, sender::startSynchronously);
155+
156+
assertThat(exception.getMessage(), is("Http sender startup did not complete in time"));
157+
}
158+
}
159+
115160
public void testCreateSender_CanCallStartAsyncMultipleTimes() throws Exception {
116161
var asyncCalls = 3;
117162
var senderFactory = new HttpRequestSender.Factory(createWithEmptySettings(threadPool), clientManager, mockClusterServiceEmpty());

0 commit comments

Comments
 (0)