Skip to content

Commit 6b160f8

Browse files
dan-rubinsteinelasticmachine
authored andcommitted
Allow timeout during trained model download process (elastic#129003)
* Allow timeout during trained model download process * Update docs/changelog/129003.yaml * Update timeout message --------- Co-authored-by: Elastic Machine <[email protected]>
1 parent 6294fdf commit 6b160f8

File tree

6 files changed

+48
-17
lines changed

6 files changed

+48
-17
lines changed

docs/changelog/129003.yaml

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pr: 129003
2+
summary: Allow timeout during trained model download process
3+
area: Machine Learning
4+
type: bug
5+
issues: []
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* 2.0.
66
*/
77

8-
package org.elasticsearch.xpack.ml.inference.assignment;
8+
package org.elasticsearch.xpack.core.ml.inference;
99

1010
import org.elasticsearch.ElasticsearchStatusException;
1111
import org.elasticsearch.rest.RestStatus;

x-pack/plugin/inference/src/main/java/org/elasticsearch/xpack/inference/services/elasticsearch/BaseElasticsearchInternalService.java

Lines changed: 39 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
import org.apache.logging.log4j.LogManager;
1111
import org.apache.logging.log4j.Logger;
1212
import org.elasticsearch.ElasticsearchStatusException;
13+
import org.elasticsearch.ElasticsearchTimeoutException;
1314
import org.elasticsearch.ExceptionsHelper;
1415
import org.elasticsearch.ResourceNotFoundException;
1516
import org.elasticsearch.action.ActionListener;
@@ -22,13 +23,15 @@
2223
import org.elasticsearch.inference.InputType;
2324
import org.elasticsearch.inference.Model;
2425
import org.elasticsearch.inference.TaskType;
26+
import org.elasticsearch.threadpool.ThreadPool;
2527
import org.elasticsearch.xpack.core.ClientHelper;
2628
import org.elasticsearch.xpack.core.ml.MachineLearningField;
2729
import org.elasticsearch.xpack.core.ml.action.GetTrainedModelsAction;
2830
import org.elasticsearch.xpack.core.ml.action.InferModelAction;
2931
import org.elasticsearch.xpack.core.ml.action.PutTrainedModelAction;
3032
import org.elasticsearch.xpack.core.ml.action.StartTrainedModelDeploymentAction;
3133
import org.elasticsearch.xpack.core.ml.action.StopTrainedModelDeploymentAction;
34+
import org.elasticsearch.xpack.core.ml.inference.ModelDeploymentTimeoutException;
3235
import org.elasticsearch.xpack.core.ml.inference.TrainedModelConfig;
3336
import org.elasticsearch.xpack.core.ml.inference.TrainedModelInput;
3437
import org.elasticsearch.xpack.core.ml.inference.TrainedModelPrefixStrings;
@@ -41,12 +44,14 @@
4144
import java.util.concurrent.ExecutorService;
4245
import java.util.function.Consumer;
4346

47+
import static org.elasticsearch.core.Strings.format;
4448
import static org.elasticsearch.xpack.core.ClientHelper.INFERENCE_ORIGIN;
4549
import static org.elasticsearch.xpack.core.ClientHelper.executeAsyncWithOrigin;
4650

4751
public abstract class BaseElasticsearchInternalService implements InferenceService {
4852

4953
protected final OriginSettingClient client;
54+
protected final ThreadPool threadPool;
5055
protected final ExecutorService inferenceExecutor;
5156
protected final Consumer<ActionListener<PreferredModelVariant>> preferredModelVariantFn;
5257
private final ClusterService clusterService;
@@ -60,6 +65,7 @@ public enum PreferredModelVariant {
6065

6166
public BaseElasticsearchInternalService(InferenceServiceExtension.InferenceServiceFactoryContext context) {
6267
this.client = new OriginSettingClient(context.client(), ClientHelper.INFERENCE_ORIGIN);
68+
this.threadPool = context.threadPool();
6369
this.inferenceExecutor = context.threadPool().executor(InferencePlugin.UTILITY_THREAD_POOL_NAME);
6470
this.preferredModelVariantFn = this::preferredVariantFromPlatformArchitecture;
6571
this.clusterService = context.clusterService();
@@ -75,6 +81,7 @@ public BaseElasticsearchInternalService(
7581
Consumer<ActionListener<PreferredModelVariant>> preferredModelVariantFn
7682
) {
7783
this.client = new OriginSettingClient(context.client(), ClientHelper.INFERENCE_ORIGIN);
84+
this.threadPool = context.threadPool();
7885
this.inferenceExecutor = context.threadPool().executor(InferencePlugin.UTILITY_THREAD_POOL_NAME);
7986
this.preferredModelVariantFn = preferredModelVariantFn;
8087
this.clusterService = context.clusterService();
@@ -96,20 +103,38 @@ public void start(Model model, TimeValue timeout, ActionListener<Boolean> finalL
96103
return;
97104
}
98105

99-
SubscribableListener.<Boolean>newForked(forkedListener -> { isBuiltinModelPut(model, forkedListener); })
100-
.<Boolean>andThen((l, modelConfigExists) -> {
101-
if (modelConfigExists == false) {
102-
putModel(model, l);
103-
} else {
104-
l.onResponse(true);
105-
}
106-
})
107-
.<Boolean>andThen((l2, modelDidPut) -> {
108-
var startRequest = esModel.getStartTrainedModelDeploymentActionRequest(timeout);
109-
var responseListener = esModel.getCreateTrainedModelAssignmentActionListener(model, l2);
110-
client.execute(StartTrainedModelDeploymentAction.INSTANCE, startRequest, responseListener);
111-
})
112-
.addListener(finalListener);
106+
// instead of a subscribably listener, use some wait to wait for the first one.
107+
var subscribableListener = SubscribableListener.<Boolean>newForked(
108+
forkedListener -> { isBuiltinModelPut(model, forkedListener); }
109+
).<Boolean>andThen((l, modelConfigExists) -> {
110+
if (modelConfigExists == false) {
111+
putModel(model, l);
112+
} else {
113+
l.onResponse(true);
114+
}
115+
}).<Boolean>andThen((l2, modelDidPut) -> {
116+
var startRequest = esModel.getStartTrainedModelDeploymentActionRequest(timeout);
117+
var responseListener = esModel.getCreateTrainedModelAssignmentActionListener(model, l2);
118+
client.execute(StartTrainedModelDeploymentAction.INSTANCE, startRequest, responseListener);
119+
});
120+
subscribableListener.addTimeout(timeout, threadPool, inferenceExecutor);
121+
subscribableListener.addListener(finalListener.delegateResponse((l, e) -> {
122+
if (e instanceof ElasticsearchTimeoutException) {
123+
l.onFailure(
124+
new ModelDeploymentTimeoutException(
125+
format(
126+
"Timed out after [%s] waiting for trained model deployment for inference endpoint [%s] to start. "
127+
+ "The inference endpoint can not be used to perform inference until the deployment has started. "
128+
+ "Use the trained model stats API to track the state of the deployment.",
129+
timeout,
130+
model.getInferenceEntityId()
131+
)
132+
)
133+
);
134+
} else {
135+
l.onFailure(e);
136+
}
137+
}));
113138

114139
} else {
115140
finalListener.onFailure(notElasticsearchModelException(model));

x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/action/TransportStartTrainedModelDeploymentAction.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
import org.elasticsearch.xpack.core.ml.action.GetTrainedModelsAction;
5353
import org.elasticsearch.xpack.core.ml.action.StartTrainedModelDeploymentAction;
5454
import org.elasticsearch.xpack.core.ml.action.StartTrainedModelDeploymentAction.TaskParams;
55+
import org.elasticsearch.xpack.core.ml.inference.ModelDeploymentTimeoutException;
5556
import org.elasticsearch.xpack.core.ml.inference.TrainedModelConfig;
5657
import org.elasticsearch.xpack.core.ml.inference.TrainedModelType;
5758
import org.elasticsearch.xpack.core.ml.inference.assignment.AllocationStatus;
@@ -65,7 +66,6 @@
6566
import org.elasticsearch.xpack.core.ml.utils.ExceptionsHelper;
6667
import org.elasticsearch.xpack.core.ml.utils.TransportVersionUtils;
6768
import org.elasticsearch.xpack.ml.MachineLearning;
68-
import org.elasticsearch.xpack.ml.inference.assignment.ModelDeploymentTimeoutException;
6969
import org.elasticsearch.xpack.ml.inference.assignment.TrainedModelAssignmentService;
7070
import org.elasticsearch.xpack.ml.inference.persistence.TrainedModelDefinitionDoc;
7171
import org.elasticsearch.xpack.ml.notifications.InferenceAuditor;

x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/InferenceWaitForAllocation.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@
1616
import org.elasticsearch.rest.RestStatus;
1717
import org.elasticsearch.tasks.TaskId;
1818
import org.elasticsearch.xpack.core.ml.action.InferModelAction;
19+
import org.elasticsearch.xpack.core.ml.inference.ModelDeploymentTimeoutException;
1920
import org.elasticsearch.xpack.core.ml.inference.assignment.RoutingInfo;
2021
import org.elasticsearch.xpack.core.ml.inference.assignment.RoutingState;
2122
import org.elasticsearch.xpack.core.ml.inference.assignment.TrainedModelAssignment;
2223
import org.elasticsearch.xpack.core.ml.inference.assignment.TrainedModelAssignmentMetadata;
2324
import org.elasticsearch.xpack.core.ml.utils.ExceptionsHelper;
24-
import org.elasticsearch.xpack.ml.inference.assignment.ModelDeploymentTimeoutException;
2525
import org.elasticsearch.xpack.ml.inference.assignment.TrainedModelAssignmentService;
2626

2727
import java.util.HashMap;

x-pack/plugin/ml/src/main/java/org/elasticsearch/xpack/ml/inference/assignment/TrainedModelAssignmentService.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@
2929
import org.elasticsearch.xpack.core.ml.action.CreateTrainedModelAssignmentAction;
3030
import org.elasticsearch.xpack.core.ml.action.DeleteTrainedModelAssignmentAction;
3131
import org.elasticsearch.xpack.core.ml.action.UpdateTrainedModelAssignmentRoutingInfoAction;
32+
import org.elasticsearch.xpack.core.ml.inference.ModelDeploymentTimeoutException;
3233
import org.elasticsearch.xpack.core.ml.inference.assignment.TrainedModelAssignment;
3334
import org.elasticsearch.xpack.core.ml.inference.assignment.TrainedModelAssignmentMetadata;
3435

0 commit comments

Comments
 (0)