Skip to content

Commit 0691426

Browse files
authored
[ML] Skip Usage stats update when ML is disabled (elastic#121559) (elastic#121766)
Do not call ML's GetDeploymentStatsAction API when ML is disabled in the cluster, instead return the inference configurations as-is. Fix elastic#121532
1 parent 53bd1dc commit 0691426

File tree

3 files changed

+87
-1
lines changed

3 files changed

+87
-1
lines changed

docs/changelog/121559.yaml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
pr: 121559
2+
summary: Skip Usage stats update when ML is disabled
3+
area: Machine Learning
4+
type: bug
5+
issues:
6+
- 121532

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

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
import org.elasticsearch.action.ActionListener;
1616
import org.elasticsearch.common.logging.DeprecationCategory;
1717
import org.elasticsearch.common.logging.DeprecationLogger;
18+
import org.elasticsearch.common.settings.Settings;
1819
import org.elasticsearch.common.util.LazyInitializable;
1920
import org.elasticsearch.core.Nullable;
2021
import org.elasticsearch.core.TimeValue;
@@ -33,6 +34,7 @@
3334
import org.elasticsearch.inference.UnifiedCompletionRequest;
3435
import org.elasticsearch.inference.configuration.SettingsConfigurationFieldType;
3536
import org.elasticsearch.rest.RestStatus;
37+
import org.elasticsearch.xpack.core.XPackSettings;
3638
import org.elasticsearch.xpack.core.inference.results.InferenceTextEmbeddingFloatResults;
3739
import org.elasticsearch.xpack.core.inference.results.RankedDocsResults;
3840
import org.elasticsearch.xpack.core.inference.results.SparseEmbeddingResults;
@@ -110,8 +112,11 @@ public class ElasticsearchInternalService extends BaseElasticsearchInternalServi
110112
private static final Logger logger = LogManager.getLogger(ElasticsearchInternalService.class);
111113
private static final DeprecationLogger DEPRECATION_LOGGER = DeprecationLogger.getLogger(ElasticsearchInternalService.class);
112114

115+
private final Settings settings;
116+
113117
public ElasticsearchInternalService(InferenceServiceExtension.InferenceServiceFactoryContext context) {
114118
super(context);
119+
this.settings = context.settings();
115120
}
116121

117122
// for testing
@@ -120,6 +125,7 @@ public ElasticsearchInternalService(InferenceServiceExtension.InferenceServiceFa
120125
Consumer<ActionListener<PreferredModelVariant>> platformArch
121126
) {
122127
super(context, platformArch);
128+
this.settings = context.settings();
123129
}
124130

125131
@Override
@@ -837,12 +843,17 @@ public List<DefaultConfigId> defaultConfigIds() {
837843

838844
@Override
839845
public void updateModelsWithDynamicFields(List<Model> models, ActionListener<List<Model>> listener) {
840-
841846
if (models.isEmpty()) {
842847
listener.onResponse(models);
843848
return;
844849
}
845850

851+
// if ML is disabled, do not update Deployment Stats (there won't be changes)
852+
if (XPackSettings.MACHINE_LEARNING_ENABLED.get(settings) == false) {
853+
listener.onResponse(models);
854+
return;
855+
}
856+
846857
var modelsByDeploymentIds = new HashMap<String, ElasticsearchInternalModel>();
847858
for (var model : models) {
848859
assert model instanceof ElasticsearchInternalModel;

x-pack/plugin/inference/src/test/java/org/elasticsearch/xpack/inference/services/elasticsearch/ElasticsearchInternalServiceTests.java

Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
import org.elasticsearch.ElasticsearchStatusException;
1414
import org.elasticsearch.action.ActionListener;
1515
import org.elasticsearch.action.LatchedActionListener;
16+
import org.elasticsearch.action.support.ActionTestUtils;
1617
import org.elasticsearch.action.support.PlainActionFuture;
1718
import org.elasticsearch.client.internal.Client;
1819
import org.elasticsearch.cluster.service.ClusterService;
@@ -46,12 +47,14 @@
4647
import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceEmbeddingSparse;
4748
import org.elasticsearch.xpack.core.inference.results.ChunkedInferenceError;
4849
import org.elasticsearch.xpack.core.ml.MachineLearningField;
50+
import org.elasticsearch.xpack.core.ml.action.GetDeploymentStatsAction;
4951
import org.elasticsearch.xpack.core.ml.action.GetTrainedModelsAction;
5052
import org.elasticsearch.xpack.core.ml.action.InferModelAction;
5153
import org.elasticsearch.xpack.core.ml.action.InferTrainedModelDeploymentAction;
5254
import org.elasticsearch.xpack.core.ml.action.PutTrainedModelAction;
5355
import org.elasticsearch.xpack.core.ml.inference.TrainedModelConfig;
5456
import org.elasticsearch.xpack.core.ml.inference.TrainedModelPrefixStrings;
57+
import org.elasticsearch.xpack.core.ml.inference.assignment.AssignmentStats;
5558
import org.elasticsearch.xpack.core.ml.inference.results.ErrorInferenceResults;
5659
import org.elasticsearch.xpack.core.ml.inference.results.MlTextEmbeddingResults;
5760
import org.elasticsearch.xpack.core.ml.inference.results.MlTextEmbeddingResultsTests;
@@ -67,11 +70,13 @@
6770
import org.elasticsearch.xpack.inference.chunking.EmbeddingRequestChunker;
6871
import org.elasticsearch.xpack.inference.chunking.WordBoundaryChunkingSettings;
6972
import org.elasticsearch.xpack.inference.services.ServiceFields;
73+
import org.hamcrest.Matchers;
7074
import org.junit.After;
7175
import org.junit.Before;
7276
import org.mockito.ArgumentCaptor;
7377
import org.mockito.Mockito;
7478

79+
import java.io.IOException;
7580
import java.util.ArrayList;
7681
import java.util.Arrays;
7782
import java.util.EnumSet;
@@ -81,12 +86,14 @@
8186
import java.util.Optional;
8287
import java.util.Set;
8388
import java.util.concurrent.CountDownLatch;
89+
import java.util.concurrent.TimeUnit;
8490
import java.util.concurrent.atomic.AtomicBoolean;
8591
import java.util.concurrent.atomic.AtomicInteger;
8692
import java.util.concurrent.atomic.AtomicReference;
8793

8894
import static org.elasticsearch.common.xcontent.XContentHelper.toXContent;
8995
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent;
96+
import static org.elasticsearch.xpack.core.ml.action.GetTrainedModelsStatsAction.Response.RESULTS_FIELD;
9097
import static org.elasticsearch.xpack.inference.chunking.ChunkingSettingsTests.createRandomChunkingSettingsMap;
9198
import static org.elasticsearch.xpack.inference.services.elasticsearch.ElasticsearchInternalService.MULTILINGUAL_E5_SMALL_MODEL_ID;
9299
import static org.elasticsearch.xpack.inference.services.elasticsearch.ElasticsearchInternalService.MULTILINGUAL_E5_SMALL_MODEL_ID_LINUX_X86;
@@ -101,6 +108,7 @@
101108
import static org.mockito.ArgumentMatchers.same;
102109
import static org.mockito.Mockito.doAnswer;
103110
import static org.mockito.Mockito.mock;
111+
import static org.mockito.Mockito.verify;
104112
import static org.mockito.Mockito.when;
105113

106114
public class ElasticsearchInternalServiceTests extends ESTestCase {
@@ -1604,6 +1612,67 @@ public void testGetConfiguration() throws Exception {
16041612
}
16051613
}
16061614

1615+
public void testUpdateWithoutMlEnabled() throws IOException, InterruptedException {
1616+
var cs = mock(ClusterService.class);
1617+
var cSettings = new ClusterSettings(Settings.EMPTY, Set.of(MachineLearningField.MAX_LAZY_ML_NODES));
1618+
when(cs.getClusterSettings()).thenReturn(cSettings);
1619+
var context = new InferenceServiceExtension.InferenceServiceFactoryContext(
1620+
mock(),
1621+
threadPool,
1622+
cs,
1623+
Settings.builder().put("xpack.ml.enabled", false).build()
1624+
);
1625+
try (var service = new ElasticsearchInternalService(context)) {
1626+
var models = List.of(mock(Model.class));
1627+
var latch = new CountDownLatch(1);
1628+
service.updateModelsWithDynamicFields(models, ActionTestUtils.assertNoFailureListener(r -> {
1629+
latch.countDown();
1630+
assertThat(r, Matchers.sameInstance(models));
1631+
}));
1632+
assertTrue(latch.await(30, TimeUnit.SECONDS));
1633+
}
1634+
}
1635+
1636+
public void testUpdateWithMlEnabled() throws IOException, InterruptedException {
1637+
var deploymentId = "deploymentId";
1638+
var model = mock(ElasticsearchInternalModel.class);
1639+
when(model.mlNodeDeploymentId()).thenReturn(deploymentId);
1640+
1641+
AssignmentStats stats = mock();
1642+
when(stats.getDeploymentId()).thenReturn(deploymentId);
1643+
when(stats.getNumberOfAllocations()).thenReturn(3);
1644+
1645+
var client = mock(Client.class);
1646+
doAnswer(ans -> {
1647+
QueryPage<AssignmentStats> queryPage = new QueryPage<>(List.of(stats), 1, RESULTS_FIELD);
1648+
1649+
GetDeploymentStatsAction.Response response = mock();
1650+
when(response.getStats()).thenReturn(queryPage);
1651+
1652+
ActionListener<GetDeploymentStatsAction.Response> listener = ans.getArgument(2);
1653+
listener.onResponse(response);
1654+
return null;
1655+
}).when(client).execute(eq(GetDeploymentStatsAction.INSTANCE), any(), any());
1656+
when(client.threadPool()).thenReturn(threadPool);
1657+
1658+
var cs = mock(ClusterService.class);
1659+
var cSettings = new ClusterSettings(Settings.EMPTY, Set.of(MachineLearningField.MAX_LAZY_ML_NODES));
1660+
when(cs.getClusterSettings()).thenReturn(cSettings);
1661+
var context = new InferenceServiceExtension.InferenceServiceFactoryContext(
1662+
client,
1663+
threadPool,
1664+
cs,
1665+
Settings.builder().put("xpack.ml.enabled", true).build()
1666+
);
1667+
try (var service = new ElasticsearchInternalService(context)) {
1668+
List<Model> models = List.of(model);
1669+
var latch = new CountDownLatch(1);
1670+
service.updateModelsWithDynamicFields(models, ActionTestUtils.assertNoFailureListener(r -> latch.countDown()));
1671+
assertTrue(latch.await(30, TimeUnit.SECONDS));
1672+
verify(model).updateNumAllocations(3);
1673+
}
1674+
}
1675+
16071676
private ElasticsearchInternalService createService(Client client) {
16081677
var cs = mock(ClusterService.class);
16091678
var cSettings = new ClusterSettings(Settings.EMPTY, Set.of(MachineLearningField.MAX_LAZY_ML_NODES));

0 commit comments

Comments
 (0)