Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Undeploy models with no WorkerNodes #3380

Merged
merged 10 commits into from
Jan 28, 2025

Conversation

brianf-aws
Copy link
Contributor

@brianf-aws brianf-aws commented Jan 11, 2025

This PR aims to undeploy modelIds that have no nodes associated to them so as to keep the intention of undeploy truthful.

Description

When performing undeploy if the model has no nodes associated to it then it will reset the index to UNDEPLOY status

Here is an example of why this code change is needed

This secnario is for the PARTIALLY_DEPLOYED issue.

  1. Have nodes a,b,c,d in cluster associated with modelID:@ i.e. peform deploy on it
  2. Bring a,b down while having the syncup job running
  3. By Now sync up will make this PARTIALLY_UNDEPLOYED
  4. stop sync up
  5. Bring other 2 c,d down and bring 2 nodes (these now have new ids 1,2)
  6. bring the other two nodes back which have different ids so now the cluster has (1,2,3,4)
    But the model index says PARTIALLY_DEPLOYED and no nodes are servicing

This code fix says. If no nodes are servicing this model then I need to set the index to UNDEPLOYED no matter if its already UNDEPLOYED or not.

Related Issues

Resolves #3285

Check List

  • New functionality includes testing.
  • New functionality has been documented.
  • API changes companion pull request created.
  • Commits are signed per the DCO using --signoff.
  • Public documentation issue/PR created.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.
For more information on following Developer Certificate of Origin and signing off your commits, please check here.

bulkUpdateRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
log.info("No models service: {}", modelIds.toString());
client.bulk(bulkUpdateRequest, ActionListener.wrap(br -> { log.debug("Successfully set modelIds to UNDEPLOY in index"); }, e -> {
log.error("Failed to set modelIds to UNDEPLOY in index", e);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we send this exception back to client side ? If yes, we should pass listener to this method and add this line here

listener.onFailure(e);

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1

Copy link
Contributor Author

@brianf-aws brianf-aws Jan 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure the user is concerned with the failure? The only way I see this as a problem if the model index does not exist and user does undeploy, this might cause a write issue.

Added your sugesstion to report the failure if it cant write back to the index.

@@ -157,10 +163,36 @@ private void undeployModels(String[] targetNodeIds, String[] modelIds, ActionLis
MLUndeployModelNodesRequest mlUndeployModelNodesRequest = new MLUndeployModelNodesRequest(targetNodeIds, modelIds);

client.execute(MLUndeployModelAction.INSTANCE, mlUndeployModelNodesRequest, ActionListener.wrap(r -> {
if (r.getNodes().isEmpty()) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it make sense that when execute undeploy model, the response return no worder nodes, then set the model to undeploy.

but this doesn't fix the partially undeployed issue, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

PARTIALLY_UNDEPLOYED is a bit of a mixture of different scenarios one of them like so

  1. Have nodes a,b,c,d in cluster associated with modelID:@ i.e. peform deploy on it
  2. Bring a,b down while having the syncup job running
  3. By Now sync up will make this PARTIALLY_UNDEPLOYED
  4. stop sync up
  5. Bring other 2 c,d down and bring 2 nodes (these now have new ids 1,2)
  6. bring the other two nodes back which have different ids so now the cluster has (1,2,3,4)
    But the model index says PARTIALLY_DEPLOYED and no nodes are servicing

This code fix says. If no nodes are servicing this model then I need to set the index to UNDEPLOYED no matter if its already UNDEPLOYED or not.

@dhrubo-os
Copy link
Collaborator

Can we add unit test?

}
bulkUpdateRequest.setRefreshPolicy(WriteRequest.RefreshPolicy.IMMEDIATE);
log.info("No models service: {}", modelIds.toString());
client.bulk(bulkUpdateRequest, ActionListener.wrap(br -> { log.debug("Successfully set modelIds to UNDEPLOY in index"); }, e -> {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can return MLUndeployModelsResponse including the original nodes rather than empty. You can find some examples in the tests how to create a new MLUndeployModelsResponse.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we don't return in br -> { log.debug("Successfully set modelIds to UNDEPLOY in index"); }, it's possible that when client side receive the undeploy response, the model still on DEPLOYED state.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Im not sure how I feel about creating a new one based on the failures,I think it will be misleading. I will pass the original response r instead.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The failures should just return a message. But for the success case we should return something rather than {}

Copy link
Collaborator

@dhrubo-os dhrubo-os Jan 11, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if success case shows (to keep consistency with current output for partially deployed case):

{
"node id 1" : Not Found,
"node id 2" : Not Found
}

I don't think this will add much value from customer's POV.

But may be we can send a Success message to customer?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will still give empty response which is not accurate. Since we cannot send nodes as response in this case, lets send something to show model/models undeployed successfully. Something like

{
<model_id_1>: "UNDEPLOYED SUCCESSFULLY",
<model_id_2>: "UNDEPLOYED SUCCESSFULLY"
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We discussed internally that we would not want to send back this information as we don't want to break bwc if we send back a updated response.

Also I'm thinking if we write UNDEPLOYED Successfully, this may sound like it performed undeployement but the reality is that it is just updating the index and not performing any update on the nodes carrying the "model".

@brianf-aws brianf-aws had a problem deploying to ml-commons-cicd-env-require-approval January 11, 2025 04:36 — with GitHub Actions Failure
@brianf-aws brianf-aws had a problem deploying to ml-commons-cicd-env-require-approval January 11, 2025 04:51 — with GitHub Actions Failure
@brianf-aws brianf-aws had a problem deploying to ml-commons-cicd-env-require-approval January 11, 2025 04:51 — with GitHub Actions Failure
@brianf-aws brianf-aws temporarily deployed to ml-commons-cicd-env-require-approval January 12, 2025 04:30 — with GitHub Actions Inactive
@brianf-aws brianf-aws temporarily deployed to ml-commons-cicd-env-require-approval January 12, 2025 04:30 — with GitHub Actions Inactive
@brianf-aws
Copy link
Contributor Author

Can we add unit test?

Added 2 UTs for code fix

  1. Check that the bulk write occurred when undeploy returned {}. This is a sign that the stale model index is UNDEPLOYED
  2. Check that bulk write did not occur when some nodes have a response to the model, undeploy occured and changed index.

client.bulk(bulkRequest, ActionListener.runAfter(actionListener, () -> {
syncUpUndeployedModels(syncUpRequest);
listener.onResponse(undeployModelNodesResponse);
}));

@brianf-aws brianf-aws had a problem deploying to ml-commons-cicd-env-require-approval January 12, 2025 07:39 — with GitHub Actions Failure
@brianf-aws brianf-aws temporarily deployed to ml-commons-cicd-env-require-approval January 13, 2025 19:55 — with GitHub Actions Inactive
@mingshl mingshl added the bug Something isn't working label Jan 28, 2025
@brianf-aws
Copy link
Contributor Author

LGTM. I added 2.x backport label, did you figure out what other versions you need to backport to? I will add the labels for you

Thank you! Yes I think we can do OS.2.11 - 2.18

@brianf-aws
Copy link
Contributor Author

Sorry can we make this to 2.x ? since this works of multi-tenancy and would break every other backport

@brianf-aws
Copy link
Contributor Author

Looks like an IT is causing an issue

RestBedRockInferenceIT > test_bedrock_multimodal_model_empty_imageInput_null_textInput STANDARD_OUT
    [2025-01-28T13:06:27,997][INFO ][o.o.m.r.RestBedRockInferenceIT] [test_bedrock_multimodal_model_empty_imageInput_null_textInput] before test
Error: 25-01-28T13:06:48,987][ERROR][o.o.m.r.MLCommonsRestTestCase] [test_bedrock_multimodal_model_empty_imageInput_null_textInput] method [POST], host [http://[::1]:38167], URI [/_plugins/_ml/_predict/TEXT_EMBEDDING/UFOGrpQB2p_oggmIDsWU], status line [HTTP/1.1 400 Bad Request]
    {"error":{"root_cause":[{"type":"illegal_argument_exception","reason":"No input text or image provided"}],"type":"illegal_argument_exception","reason":"No input text or image provided"},"status":400}
    org.opensearch.client.ResponseException: method [POST], host [http://[::1]:38167], URI [/_plugins/_ml/_predict/TEXT_EMBEDDING/UFOGrpQB2p_oggmIDsWU], status line [HTTP/1.1 400 Bad Request]
    {"error":{"root_cause":[{"type":"illegal_argument_exception","reason":"No input text or image provided"}],"type":"illegal_argument_exception","reason":"No input text or image provided"},"status":400}
    	at org.opensearch.client.RestClient.convertResponse(RestClient.java:501) ~[opensearch-rest-client-3.0.0-SNAPSHOT.jar:3.0.0-SNAPSHOT]
    	at org.opensearch.client.RestClient.performRequest(RestClient.java:384) ~[opensearch-rest-client-3.0.0-SNAPSHOT.jar:3.0.0-SNAPSHOT]
    	at org.opensearch.client.RestClient.performRequest(RestClient.java:359) ~[opensearch-rest-client-3.0.0-SNAPSHOT.jar:3.0.0-SNAPSHOT]
    	at org.opensearch.ml.utils.TestHelper.makeRequest(TestHelper.java:183) ~[test/:?]
    	at org.opensearch.ml.utils.TestHelper.makeRequest(TestHelper.java:156) ~[test/:?]
    	at org.opensearch.ml.utils.TestHelper.makeRequest(TestHelper.java:145) ~[test/:?]
    	at org.opensearch.ml.rest.MLCommonsRestTestCase.predictTextEmbeddingModel(MLCommonsRestTestCase.java:925) ~[test/:?]
    	at org.opensearch.ml.rest.RestBedRockInferenceIT.test_bedrock_multimodal_model_empty_imageInput_null_textInput(RestBedRockInferenceIT.java:233) ~[test/:?]

Is this a flaky known issue if not can we merge? cc: @jngz-es, @mingshl

@dhrubo-os dhrubo-os merged commit 18bcaae into opensearch-project:main Jan 28, 2025
18 of 19 checks passed
opensearch-trigger-bot bot pushed a commit that referenced this pull request Jan 28, 2025
* undeploy models with no WorkerNodes

This commit aims to undeploy modelIds that have no nodes associated to them so as to keep the intention of undeploy truthful.

Signed-off-by: Brian Flores <[email protected]>

# Conflicts:
#	plugin/src/main/java/org/opensearch/ml/action/undeploy/TransportUndeployModelsAction.java

* Exit early when no nodes service the model

Now when entering this method its guaranteed to write to index first before sending back the MLUndeploy response. And will also send back a exception if the write back fails

Signed-off-by: Brian Flores <[email protected]>

* add UTs for undeploy stale model index fix

Added UTs for the 2 scenarios 1. Check that the bulk operation occured when no nodes are returned from the Undeploy response is , 2. Check that the bulk operation did not occur when there are nodes that have found the model within their cache.

Signed-off-by: Brian Flores <[email protected]>

* update code change with comment explaining the change

Signed-off-by: Brian Flores <[email protected]>

* add context stash/restore to write operation

Signed-off-by: Brian Flores <[email protected]>

* Apply spotless

Signed-off-by: Brian Flores <[email protected]>

* Add better logging to write request

Signed-off-by: Brian Flores <[email protected]>

* wrap exception into 5xx

Signed-off-by: Brian Flores <[email protected]>

* adapts undeploy code change to multi-tenancy feature

Signed-off-by: Brian Flores <[email protected]>

* applies spotless

Signed-off-by: Brian Flores <[email protected]>

---------

Signed-off-by: Brian Flores <[email protected]>
(cherry picked from commit 18bcaae)
Zhangxunmt pushed a commit that referenced this pull request Jan 28, 2025
* undeploy models with no WorkerNodes

This commit aims to undeploy modelIds that have no nodes associated to them so as to keep the intention of undeploy truthful.

Signed-off-by: Brian Flores <[email protected]>

# Conflicts:
#	plugin/src/main/java/org/opensearch/ml/action/undeploy/TransportUndeployModelsAction.java

* Exit early when no nodes service the model

Now when entering this method its guaranteed to write to index first before sending back the MLUndeploy response. And will also send back a exception if the write back fails

Signed-off-by: Brian Flores <[email protected]>

* add UTs for undeploy stale model index fix

Added UTs for the 2 scenarios 1. Check that the bulk operation occured when no nodes are returned from the Undeploy response is , 2. Check that the bulk operation did not occur when there are nodes that have found the model within their cache.

Signed-off-by: Brian Flores <[email protected]>

* update code change with comment explaining the change

Signed-off-by: Brian Flores <[email protected]>

* add context stash/restore to write operation

Signed-off-by: Brian Flores <[email protected]>

* Apply spotless

Signed-off-by: Brian Flores <[email protected]>

* Add better logging to write request

Signed-off-by: Brian Flores <[email protected]>

* wrap exception into 5xx

Signed-off-by: Brian Flores <[email protected]>

* adapts undeploy code change to multi-tenancy feature

Signed-off-by: Brian Flores <[email protected]>

* applies spotless

Signed-off-by: Brian Flores <[email protected]>

---------

Signed-off-by: Brian Flores <[email protected]>
(cherry picked from commit 18bcaae)

Co-authored-by: Brian Flores <[email protected]>
@opensearch-trigger-bot
Copy link
Contributor

The backport to feature/multi_tenancy failed:

The process '/usr/bin/git' failed with exit code 1

To backport manually, run these commands in your terminal:

# Fetch latest updates from GitHub
git fetch
# Create a new working tree
git worktree add .worktrees/backport-feature/multi_tenancy feature/multi_tenancy
# Navigate to the new working tree
cd .worktrees/backport-feature/multi_tenancy
# Create a new branch
git switch --create backport/backport-3380-to-feature/multi_tenancy
# Cherry-pick the merged commit of this pull request and resolve the conflicts
git cherry-pick -x --mainline 1 18bcaaeff9294372801e63f376bc7920143fa3ad
# Push it to GitHub
git push --set-upstream origin backport/backport-3380-to-feature/multi_tenancy
# Go back to the original working tree
cd ../..
# Delete the working tree
git worktree remove .worktrees/backport-feature/multi_tenancy

Then, create a pull request where the base branch is feature/multi_tenancy and the compare/head branch is backport/backport-3380-to-feature/multi_tenancy.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[BUG] Model undeploying giving empty response
8 participants