Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@ Please mark backwards incompatible changes with an exclamation mark at the start

## [Unreleased]

### Deprecated
- The `#task_by_id` method of the `Elasticsearch::Client` class.

### Added
- The `#all` method to `JayAPI::Elasticsearch::Tasks`. The method returns the
status of all running tasks on the Elasticsearch cluster.
- The `#tasks` method to `JayAPI::Elasticsearch::Client`. The method returns an
instance of `JayAPI::Elasticsearch::Tasks`, which gives the user access to the
status of the tasks running on the Elasticsearch cluster.

## [29.5.0] - 2026-02-23

### Fixed
Expand Down
1 change: 1 addition & 0 deletions lib/jay_api/elasticsearch.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
require_relative 'elasticsearch/index'
require_relative 'elasticsearch/indexes'
require_relative 'elasticsearch/indices'
require_relative 'elasticsearch/mixins'
require_relative 'elasticsearch/query_builder'
require_relative 'elasticsearch/query_results'
require_relative 'elasticsearch/response'
Expand Down
35 changes: 9 additions & 26 deletions lib/jay_api/elasticsearch/client.rb
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
# frozen_string_literal: true

require 'timeout'
require 'elasticsearch/transport/transport/errors'
require 'faraday/error'
require 'forwardable'

require_relative '../abstract/connection'
require_relative 'mixins/retriable_requests'
require_relative 'stats'
require_relative 'tasks'

module JayAPI
module Elasticsearch
Expand All @@ -17,23 +17,7 @@ module Elasticsearch
class Client
extend Forwardable

# The errors that, if raised, must cause a retry of the connection.
ERRORS = [
::Elasticsearch::Transport::Transport::ServerError,
Faraday::TimeoutError
].freeze

# Subclasses of the +Elasticsearch::Transport::Transport::ServerError+
# for which a retry doesn't make sense.
NON_RETRIABLE_ERRORS = [
::Elasticsearch::Transport::Transport::Errors::BadRequest,
::Elasticsearch::Transport::Transport::Errors::Unauthorized,
::Elasticsearch::Transport::Transport::Errors::Forbidden,
::Elasticsearch::Transport::Transport::Errors::NotFound,
::Elasticsearch::Transport::Transport::Errors::MethodNotAllowed,
::Elasticsearch::Transport::Transport::Errors::RequestEntityTooLarge,
::Elasticsearch::Transport::Transport::Errors::NotImplemented
].freeze
include JayAPI::Elasticsearch::Mixins::RetriableRequests

attr_reader :transport_client, :logger, :max_attempts, :wait_strategy

Expand Down Expand Up @@ -88,6 +72,7 @@ def delete_by_query(**args)
# parameters. If the request fails, additional retries will be performed.
# @see Elasticsearch::Client#tasks for more info about the arguments and
# the return value.
# @deprecated Use Tasks#by_id instead.
def task_by_id(**args)
retry_request { transport_client.tasks.get(**args) }
end
Expand All @@ -98,13 +83,11 @@ def stats
@stats ||= ::JayAPI::Elasticsearch::Stats.new(transport_client)
end

private

# @param [Proc] block The block to execute.
# @yieldreturn [Object] Whatever the block returns
def retry_request(&block)
Abstract::Connection.new(max_attempts: max_attempts, wait_strategy: wait_strategy.dup, logger: logger)
.retry(errors: ERRORS, except: NON_RETRIABLE_ERRORS, &block)
# @return [JayAPI::Elasticsearch::Tasks] An instance of the +Tasks+ class,
# which can be used to retrieve the status of the tasks running on the
# Elasticsearch cluster.
def tasks
@tasks ||= ::JayAPI::Elasticsearch::Tasks.new(client: self)
end
end
end
Expand Down
10 changes: 10 additions & 0 deletions lib/jay_api/elasticsearch/mixins.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
# frozen_string_literal: true

require_relative 'mixins/retriable_requests'

module JayAPI
module Elasticsearch
# A namespace for Elasticsearch related mixins.
module Mixins; end
end
end
79 changes: 79 additions & 0 deletions lib/jay_api/elasticsearch/mixins/retriable_requests.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# frozen_string_literal: true

require 'elasticsearch/transport/transport/errors'

require_relative '../../abstract/connection'

module JayAPI
module Elasticsearch
module Mixins
# A mixin that allows the including class to retry requests to
# Elasticsearch by leveraging the +Abstract::Connection+ class'
# capabilities.
module RetriableRequests
# The errors that, if raised, must cause a retry of the connection.
RETRIABLE_ERRORS = [
::Elasticsearch::Transport::Transport::ServerError,
Faraday::TimeoutError
].freeze

# Subclasses of the +Elasticsearch::Transport::Transport::ServerError+
# for which a retry doesn't make sense.
NON_RETRIABLE_ERRORS = [
::Elasticsearch::Transport::Transport::Errors::BadRequest,
::Elasticsearch::Transport::Transport::Errors::Unauthorized,
::Elasticsearch::Transport::Transport::Errors::Forbidden,
::Elasticsearch::Transport::Transport::Errors::NotFound,
::Elasticsearch::Transport::Transport::Errors::MethodNotAllowed,
::Elasticsearch::Transport::Transport::Errors::RequestEntityTooLarge,
::Elasticsearch::Transport::Transport::Errors::NotImplemented
].freeze

# @return [Integer] The maximum number of times a request should be
# retried before giving up.
def max_attempts
raise_not_implemented(__method__)
end

# @return [JayAPI::Elasticsearch::WaitStrategy] The waiting strategy for
# retries.
def wait_strategy
raise_not_implemented(__method__)
end

# @return [Logging::Logger] A logger to log messages.
def logger
raise_not_implemented(__method__)
end

# @return [Array<Class>] The array of errors that, if raised, must cause
# a retry of the request.
def retriable_errors
RETRIABLE_ERRORS
end

# @return [Array<Class>] An array of subclasses of the
# +Elasticsearch::Transport::Transport::ServerError+ for which a retry
# doesn't make sense.
def non_retriable_errors
NON_RETRIABLE_ERRORS
end

private

# Uses the +Abstract::Connection+ class to retry the request enclosed in
# the given block.
def retry_request(&)
Abstract::Connection.new(max_attempts:, wait_strategy: wait_strategy.dup, logger:)
.retry(errors: retriable_errors, except: non_retriable_errors, &)
end

# @raise [NotImplementedError] Is always raised with the appropriate
# error message.
def raise_not_implemented(method)
raise NotImplementedError, "Please implement the method ##{method} in #{self.class}"
end
end
end
end
end
44 changes: 42 additions & 2 deletions lib/jay_api/elasticsearch/tasks.rb
Original file line number Diff line number Diff line change
@@ -1,22 +1,52 @@
# frozen_string_literal: true

require 'active_support'
require 'active_support/core_ext/enumerable'
require 'active_support/core_ext/hash/indifferent_access'
require 'forwardable'

require_relative 'mixins/retriable_requests'

module JayAPI
module Elasticsearch
# Represents Elasticsearch tasks. Returns information about the tasks
# currently executing in the cluster.
# TODO: Add #all [JAY-593]
class Tasks
extend Forwardable
include ::JayAPI::Elasticsearch::Mixins::RetriableRequests

attr_reader :client

def_delegators :client, :transport_client, :max_attempts, :wait_strategy, :logger

# @param [JayAPI::Elasticsearch::Client] client The Elasticsearch Client
# object
def initialize(client:)
@client = client
end

# Gets the list of tasks running on the Elasticsearch cluster.
# For more information about this endpoint and the parameters please see:
# https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-tasks-list
# @param [Array<String>] actions A list of actions. Only tasks matching
# these actions will be returned, if no task matches the result will be
# empty.
# @param [Boolean] detailed Whether or not the result should include task
# details or not.
# @return [Hash] A hash with the list of tasks running on the
# Elasticsearch cluster.
def all(actions: nil, detailed: false)

Check failure on line 38 in lib/jay_api/elasticsearch/tasks.rb

View workflow job for this annotation

GitHub Actions / lint

[reek] reported by reviewdog 🐶 BooleanParameter: JayAPI::Elasticsearch::Tasks#all has boolean parameter 'detailed' [https://github.com/troessner/reek/blob/v6.5.0/docs/Boolean-Parameter.md] Raw Output: lib/jay_api/elasticsearch/tasks.rb:38: BooleanParameter: JayAPI::Elasticsearch::Tasks#all has boolean parameter 'detailed' [https://github.com/troessner/reek/blob/v6.5.0/docs/Boolean-Parameter.md]
# Needed because unlike many Elasticsearch methods Tasks#list doesn't
# call #listify over +actions+.
actions = actions&.then do |value|
value.is_a?(Array) ? value.join(',') : value
end

retry_request do
tasks_client.list({ actions:, detailed: }.compact_blank)
end
end

# Retrieves info about the task with the passed +task_id+
# For more information on how to build the query please refer to the
# Elasticsearch DSL documentation:
Expand All @@ -29,7 +59,17 @@
# @raise [Elasticsearch::Transport::Transport::ServerError] If the
# query fails.
def by_id(task_id)
client.task_by_id(task_id: task_id, wait_for_completion: true).deep_symbolize_keys
retry_request do
tasks_client.get(task_id:, wait_for_completion: true).deep_symbolize_keys
end
end

private

# @return [Elasticsearch::API::Tasks::TasksClient] The client used to
# access tasks-related information.
def tasks_client
@tasks_client ||= transport_client.tasks
end
end
end
Expand Down
23 changes: 23 additions & 0 deletions spec/integration/jay_api/elasticsearch/client_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -318,4 +318,27 @@
expect(method_call).to be(stats)
end
end

describe '#tasks' do
subject(:method_call) { client.tasks }

let(:tasks) do
instance_double(
JayAPI::Elasticsearch::Tasks
)
end

before do
allow(JayAPI::Elasticsearch::Tasks).to receive(:new).and_return(tasks)
end

it "initializes an instance of JayAPI::Elasticsearch::Tasks and passes a reference to 'self'" do
expect(JayAPI::Elasticsearch::Tasks).to receive(:new).with(client:)
method_call
end

it 'returns the JayAPI::Elasticsearch::Tasks instance' do
expect(method_call).to be(tasks)
end
end
end
Loading