Skip to content

Commit

Permalink
Moved ignore 404 on deletion to client options.
Browse files Browse the repository at this point in the history
Signed-off-by: Theo Truong <[email protected]>
  • Loading branch information
nhtruong committed Feb 27, 2025
1 parent 0c25b91 commit 4af1ebd
Show file tree
Hide file tree
Showing 57 changed files with 97 additions and 173 deletions.
12 changes: 6 additions & 6 deletions UPGRADING.md
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
# Upgrading
Major versions of OpenSearch introduce breaking changes that require careful upgrades of the client. Check the [Compatibility](COMPATIBILITY.md) doc to see which version of the client should be used against your OpenSearch cluster.

### Upgrade to OpenSearch Ruby 4
OpenSearch Ruby 4 drops support for Ruby 2.x. If you are using Ruby 2.x, you should upgrade to Ruby 3.x before upgrading to OpenSearch Ruby 4.


### Upgrade to OpenSearch Ruby 3
## Upgrade to OpenSearch Ruby 4
- OpenSearch Ruby 4 drops support for Ruby 2.x. If you are using Ruby 2.x, you should upgrade to Ruby 3.x before upgrading to OpenSearch Ruby 4.
- OpenSearch Ruby 4 has a different implementation of the `ignore 404 error` feature on all delete actions. Instead of passing `ingore: 404` as if it is a query parameter for each API action, this feature can now be toggled on and off (off by default) during the client instance instantiation. If you are using this feature, you should review the [Idempotent Delete](./guides/idempotent_delete.md) guide for the changes.
- OpenSearch Ruby 4 received a major refactor to remove middle-man `perform_request` methods. While this does not affect the vast majority of use cases, applications or wrappers that rely on these methods should be updated. For more information, check the `How the perform_request method is invoked` section of this [PR](https://github.com/opensearch-project/opensearch-ruby/pull/261).
## Upgrade to OpenSearch Ruby 3
In Version 3 of the OpenSearch Ruby client, we have added the `api` and `transport` modules as the core components of the gem, instead of treating them as separate gems that are required by the `opensearch-ruby` gem. This removes the confusions around compatibility between the ruby client, its legacy dependencies, and the OpenSearch cluster.

`opensearch-dsl` has also been moved into `opensearch-ruby` 3.0. If your application uses `opensearch-dsl`, you should now remove this gem from your Gemfile or gemspec.

We don't expect the upgrade to OpenSearch Ruby 3 to be a breaking change for the vast majority of use cases, and you do not have to make any changes to your application before the upgrade. On your development environment, you might want to perform a `bundle clean` to remove `opensearch-api`, `opensearch-transport`, and `opensearch-dsl` gems after the upgrade.

### Upgrade to OpenSearch Ruby 2
## Upgrade to OpenSearch Ruby 2
While `opensearch-ruby-client` 2.x works against the latest OpenSearch 1.x, certain deprecated features removed in OpenSearch 2.0 have also been removed from the client. So, only upgrade to `opensearch-ruby` gem to 2.x if you are also upgrading your cluster to OpenSearch 2.0.
6 changes: 1 addition & 5 deletions api_generator/lib/generators/action_generator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -72,10 +72,6 @@ def bulk_body
@action.arguments.find { |arg| arg.name == 'body' }&.schema&.type == 'array'
end

def support_ignore
@action.http_verbs == %w[DELETE]
end

def path_params
@action.path_params.map { |arg| { name: arg.name } }
.tap { |args| args.last&.[]=('_blank_line', true) }
Expand All @@ -89,7 +85,7 @@ def perform_request
args = 'method, url, args, body, headers'
return "transport.perform_ping_request #{args}" if @action.full_name == 'ping'
return "transport.perform_head_request #{args}" if @action.http_verbs == %w[HEAD]
return "transport.perform_delete_request #{args}, ignore.include?(404)" if @action.http_verbs == %w[DELETE]
return "transport.perform_delete_request #{args}" if @action.http_verbs == %w[DELETE]
"transport.perform_request(#{args}).body"
end
end
6 changes: 0 additions & 6 deletions api_generator/lib/templates/action.mustache
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,6 @@ module OpenSearch
{{#argument_descriptions}}
# @option args [{{{data_type}}}] :{{{name}}}{{#required}} *Required*{{/required}}{{#deprecated}} DEPRECATED{{/deprecated}}{{#default}} (default: {{{default}}}){{/default}}{{#description}} {{{description}}}{{/description}}
{{/argument_descriptions}}
{{#support_ignore}}
# @option args [List] :ignore set to [404] to ignore server's NOT FOUND error for this request
{{/support_ignore}}
{{#api_reference}}
#
# {API Reference}[{{{api_reference}}}]
Expand All @@ -33,9 +30,6 @@ module OpenSearch

{{/_blank_line}}
{{/path_params}}
{{#support_ignore}}
ignore = args.delete('ignore') || []
{{/support_ignore}}
{{#bulk_body}}
headers = (args.delete('headers') || {}).merge('Content-Type' => 'application/x-ndjson')
body = Utils.bulkify(args.delete('body'))
Expand Down
5 changes: 1 addition & 4 deletions guides/document_lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,10 +113,7 @@ To delete a document, use the `delete` API action. The following code deletes th
```ruby
client.delete(index: index, id: 1)
```
By default, the `delete` action is not idempotent. If you try to delete a document that does not exist, or delete the same document twice, you will run into Not Found (404) error. You can make the `delete` action idempotent by setting the `ignore` parameter to `404`:
```ruby
client.delete(index: index, id: 1, ignore: 404)
```
By default, the `delete` action is not idempotent. If you try to delete a document that does not exist, or delete the same document twice, you will run into 404/NotFound error. You can make the `delete` action idempotent across the client instance. Check the [Idempotent Delete](idempotent_delete.md) guide for more information.

### Delete multiple documents by query
To delete documents that match a query, use the `delete_by_query` API action. The following code deletes all documents with `year` greater than 2023:
Expand Down
21 changes: 21 additions & 0 deletions guides/idempotent_delete.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# Idempotent Delete
Most OpenSearch API endpoints will throw a 404/NotFound error when deleting a resource that no longer exists. That is, before performing a deletion, you have to check if the resource exists. That is, the delete actions is not idempotent on OpenSearch. This can be cumbersome and error-prone. The Ruby client provides `:ignore_404_on_delete` option to make delete actions idempotent. When set to `true` (default to `false`), the client will ignore the 404 error if the deleted resource does not exist, and return `false` instead.


Let's create a client instance with the `:ignore_404_on_delete` option set to `true`:
```ruby
require 'opensearch-ruby'
client = OpenSearch::Client.new(
host: 'https://admin:admin@localhost:9200',
transport_options: { ssl: { verify: false } },
ignore_404_on_delete: true
)
```
Now you can delete a resource without checking if it exists, or delete the same resource several times without error:
```ruby
client.indices.create(index: :movies)
client.delete(index: :movies, id: 1)
client.delete(index: :movies, id: 1)
client.indices.delete(index: :movies)
client.indices.delete(index: [:moves, :books])
```
6 changes: 3 additions & 3 deletions guides/index_lifecycle.md
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ The response body contains the index's settings and mappings:
}
}
}
}
}
```
### Delete an Index
Let's delete the `movies` index by using the `indices.delete` API action:
Expand All @@ -131,9 +131,9 @@ client.indices.delete(index: :movies)
We can also delete multiple indices at once:

```ruby
client.indices.delete(index: [:movies, :paintings, :burner], ignore: 404)
client.indices.delete(index: [:movies, :paintings, :burner])
```
Notice that we are passing `ignore: 404` to the request. This tells the client to ignore the `404` error if the index doesn't exist for deletion. Without it, the above `delete` request will throw an error because the `movies` index has already been deleted in the previous example.
By default, the `indices.delete` action is not idempotent. If you try to delete an index that does not exist, or delete the same indices twice, you will run into 404/NotFound error. You can make the `indices.delete` action idempotent across the client instance. Check the [Idempotent Delete](idempotent_delete.md) guide for more information.

## Cleanup

Expand Down
4 changes: 1 addition & 3 deletions lib/opensearch/api/actions/asynchronous_search/delete.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,21 +16,19 @@ module Actions
# Deletes any responses from an asynchronous search.
#
# @option args [String] :id *Required*
# @option args [List] :ignore set to [404] to ignore server's NOT FOUND error for this request
def delete(args = {})
args = Utils.clone_and_normalize_arguments(args)
raise ArgumentError, "Required argument 'id' missing" if args['id'].nil?

_id = args.delete('id')

ignore = args.delete('ignore') || []
headers = args.delete('headers') || {}
body = args.delete('body')
method = 'DELETE'
url = Utils.build_url('_plugins/_asynchronous_search', _id)

Utils.validate_query_params! args
transport.perform_delete_request method, url, args, body, headers, ignore.include?(404)
transport.perform_delete_request method, url, args, body, headers
end
end
end
Expand Down
4 changes: 1 addition & 3 deletions lib/opensearch/api/actions/clear_scroll.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,17 @@ module Actions
#
# @option args [Enumerable<String>, String] :scroll_id DEPRECATED Comma-separated list of scroll IDs to clear. To clear all scroll IDs, use `_all`.
# @option args [Hash] :body Comma-separated list of scroll IDs to clear if none was specified using the `scroll_id` parameter
# @option args [List] :ignore set to [404] to ignore server's NOT FOUND error for this request
def clear_scroll(args = {})
args = Utils.clone_and_normalize_arguments(args)
_scroll_id = args.delete('scroll_id')

ignore = args.delete('ignore') || []
headers = args.delete('headers') || {}
body = args.delete('body')
method = 'DELETE'
url = Utils.build_url('_search/scroll', _scroll_id)

Utils.validate_query_params! args
transport.perform_delete_request method, url, args, body, headers, ignore.include?(404)
transport.perform_delete_request method, url, args, body, headers
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,21 +19,19 @@ module Actions
# @option args [String] :cluster_manager_timeout Operation timeout for connection to cluster-manager node.
# @option args [String] :master_timeout DEPRECATED A duration. Units can be `nanos`, `micros`, `ms` (milliseconds), `s` (seconds), `m` (minutes), `h` (hours) and `d` (days). Also accepts "0" without a unit and "-1" to indicate an unspecified value.
# @option args [String] :timeout A duration. Units can be `nanos`, `micros`, `ms` (milliseconds), `s` (seconds), `m` (minutes), `h` (hours) and `d` (days). Also accepts "0" without a unit and "-1" to indicate an unspecified value.
# @option args [List] :ignore set to [404] to ignore server's NOT FOUND error for this request
def delete_component_template(args = {})
args = Utils.clone_and_normalize_arguments(args)
raise ArgumentError, "Required argument 'name' missing" if args['name'].nil?

_name = args.delete('name')

ignore = args.delete('ignore') || []
headers = args.delete('headers') || {}
body = args.delete('body')
method = 'DELETE'
url = Utils.build_url('_component_template', _name)

Utils.validate_query_params! args, DELETE_COMPONENT_TEMPLATE_QUERY_PARAMS
transport.perform_delete_request method, url, args, body, headers, ignore.include?(404)
transport.perform_delete_request method, url, args, body, headers
end

DELETE_COMPONENT_TEMPLATE_QUERY_PARAMS = Set.new(%w[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,15 @@ module Cluster
module Actions
# Recommissions a decommissioned zone.
#
# @option args [List] :ignore set to [404] to ignore server's NOT FOUND error for this request
def delete_decommission_awareness(args = {})
args = Utils.clone_and_normalize_arguments(args)
ignore = args.delete('ignore') || []
headers = args.delete('headers') || {}
body = args.delete('body')
method = 'DELETE'
url = '_cluster/decommission/awareness'

Utils.validate_query_params! args
transport.perform_delete_request method, url, args, body, headers, ignore.include?(404)
transport.perform_delete_request method, url, args, body, headers
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,15 @@ module Actions
# Clears any cluster voting configuration exclusions.
#
# @option args [Boolean] :wait_for_removal (default: true) Specifies whether to wait for all excluded nodes to be removed from the cluster before clearing the voting configuration exclusions list. When `true`, all excluded nodes are removed from the cluster before this API takes any action. When `false`, the voting configuration exclusions list is cleared even if some excluded nodes are still in the cluster.
# @option args [List] :ignore set to [404] to ignore server's NOT FOUND error for this request
def delete_voting_config_exclusions(args = {})
args = Utils.clone_and_normalize_arguments(args)
ignore = args.delete('ignore') || []
headers = args.delete('headers') || {}
body = args.delete('body')
method = 'DELETE'
url = '_cluster/voting_config_exclusions'

Utils.validate_query_params! args, DELETE_VOTING_CONFIG_EXCLUSIONS_QUERY_PARAMS
transport.perform_delete_request method, url, args, body, headers, ignore.include?(404)
transport.perform_delete_request method, url, args, body, headers
end

DELETE_VOTING_CONFIG_EXCLUSIONS_QUERY_PARAMS = Set.new(%w[
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,15 @@ module Actions
# Delete weighted shard routing weights.
#
# @option args [Hash] :body
# @option args [List] :ignore set to [404] to ignore server's NOT FOUND error for this request
def delete_weighted_routing(args = {})
args = Utils.clone_and_normalize_arguments(args)
ignore = args.delete('ignore') || []
headers = args.delete('headers') || {}
body = args.delete('body')
method = 'DELETE'
url = '_cluster/routing/awareness/weights'

Utils.validate_query_params! args
transport.perform_delete_request method, url, args, body, headers, ignore.include?(404)
transport.perform_delete_request method, url, args, body, headers
end
end
end
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,22 +20,20 @@ module Actions
# @option args [String] :cluster_manager_timeout Operation timeout for connection to cluster-manager node.
# @option args [String] :master_timeout DEPRECATED Specify timeout for connection to cluster manager.
# @option args [String] :timeout Explicit operation timeout.
# @option args [List] :ignore set to [404] to ignore server's NOT FOUND error for this request
def delete_dangling_index(args = {})
args = Utils.clone_and_normalize_arguments(args)
raise ArgumentError, "Required argument 'index_uuid' missing" if args['index_uuid'].nil?
raise ArgumentError, "Required argument 'accept_data_loss' missing" if args['accept_data_loss'].nil?

_index_uuid = args.delete('index_uuid')

ignore = args.delete('ignore') || []
headers = args.delete('headers') || {}
body = args.delete('body')
method = 'DELETE'
url = Utils.build_url('_dangling', _index_uuid)

Utils.validate_query_params! args, DELETE_DANGLING_INDEX_QUERY_PARAMS
transport.perform_delete_request method, url, args, body, headers, ignore.include?(404)
transport.perform_delete_request method, url, args, body, headers
end

DELETE_DANGLING_INDEX_QUERY_PARAMS = Set.new(%w[
Expand Down
4 changes: 1 addition & 3 deletions lib/opensearch/api/actions/delete.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ module Actions
# @option args [Integer] :version Explicit version number for concurrency control. The specified version must match the current version of the document for the request to succeed.
# @option args [String] :version_type Specific version type: `external`, `external_gte`.
# @option args [Integer, String] :wait_for_active_shards The number of shard copies that must be active before proceeding with the operation. Set to `all` or any positive integer up to the total number of shards in the index (`number_of_replicas+1`).
# @option args [List] :ignore set to [404] to ignore server's NOT FOUND error for this request
def delete(args = {})
args = Utils.clone_and_normalize_arguments(args)
raise ArgumentError, "Required argument 'id' missing" if args['id'].nil?
Expand All @@ -34,14 +33,13 @@ def delete(args = {})
_id = args.delete('id')
_index = args.delete('index')

ignore = args.delete('ignore') || []
headers = args.delete('headers') || {}
body = args.delete('body')
method = 'DELETE'
url = Utils.build_url(_index, '_doc', _id)

Utils.validate_query_params! args, DELETE_QUERY_PARAMS
transport.perform_delete_request method, url, args, body, headers, ignore.include?(404)
transport.perform_delete_request method, url, args, body, headers
end

DELETE_QUERY_PARAMS = Set.new(%w[
Expand Down
4 changes: 1 addition & 3 deletions lib/opensearch/api/actions/delete_all_pits.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,17 +15,15 @@ module Root
module Actions
# Deletes all active point in time searches.
#
# @option args [List] :ignore set to [404] to ignore server's NOT FOUND error for this request
def delete_all_pits(args = {})
args = Utils.clone_and_normalize_arguments(args)
ignore = args.delete('ignore') || []
headers = args.delete('headers') || {}
body = args.delete('body')
method = 'DELETE'
url = '_search/point_in_time/_all'

Utils.validate_query_params! args
transport.perform_delete_request method, url, args, body, headers, ignore.include?(404)
transport.perform_delete_request method, url, args, body, headers
end
end
end
Expand Down
4 changes: 1 addition & 3 deletions lib/opensearch/api/actions/delete_pit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,17 +16,15 @@ module Actions
# Deletes one or more point in time searches based on the IDs passed.
#
# @option args [Hash] :body The point-in-time ids to be deleted
# @option args [List] :ignore set to [404] to ignore server's NOT FOUND error for this request
def delete_pit(args = {})
args = Utils.clone_and_normalize_arguments(args)
ignore = args.delete('ignore') || []
headers = args.delete('headers') || {}
body = args.delete('body')
method = 'DELETE'
url = '_search/point_in_time'

Utils.validate_query_params! args
transport.perform_delete_request method, url, args, body, headers, ignore.include?(404)
transport.perform_delete_request method, url, args, body, headers
end
end
end
Expand Down
Loading

0 comments on commit 4af1ebd

Please sign in to comment.