Skip to content

Commit 222c8fb

Browse files
[JAY-749] Add the #all method to Elasticsearch::Tasks
The method returns a Hash with information about the tasks running on the Elasticsearch cluster. The method accepts an optional argument to filter the tasks by their action type and a boolean argument that causes Elasticsearch to add detailed information about each task to the response when set to true.
1 parent bd04e72 commit 222c8fb

3 files changed

Lines changed: 194 additions & 9 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@ Please mark backwards incompatible changes with an exclamation mark at the start
1212
- The `#task_by_id` method of the `Elasticsearch::Client` class.
1313

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

lib/jay_api/elasticsearch/tasks.rb

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
# frozen_string_literal: true
22

33
require 'active_support'
4+
require 'active_support/core_ext/enumerable'
45
require 'active_support/core_ext/hash/indifferent_access'
56
require 'forwardable'
67

@@ -10,7 +11,6 @@ module JayAPI
1011
module Elasticsearch
1112
# Represents Elasticsearch tasks. Returns information about the tasks
1213
# currently executing in the cluster.
13-
# TODO: Add #all [JAY-593]
1414
class Tasks
1515
extend Forwardable
1616
include ::JayAPI::Elasticsearch::Mixins::RetriableRequests
@@ -25,6 +25,28 @@ def initialize(client:)
2525
@client = client
2626
end
2727

28+
# Gets the list of tasks running on the Elasticsearch cluster.
29+
# For more information about this endpoint and the parameters please see:
30+
# https://www.elastic.co/docs/api/doc/elasticsearch/operation/operation-tasks-list
31+
# @param [Array<String>] actions A list of actions. Only tasks matching
32+
# these actions will be returned, if no task matches the result will be
33+
# empty.
34+
# @param [Boolean] detailed Whether or not the result should include task
35+
# details or not.
36+
# @return [Hash] A hash with the list of tasks running on the
37+
# Elasticsearch cluster.
38+
def all(actions: nil, detailed: false)
39+
retry_request do
40+
# Needed because unlike many Elasticsearch methods Tasks#list doesn't
41+
# call #listify over +actions+.
42+
actions = actions&.then do |value|
43+
value.is_a?(Array) ? value.join(',') : value
44+
end
45+
46+
tasks_client.list({ actions:, detailed: }.compact_blank)
47+
end
48+
end
49+
2850
# Retrieves info about the task with the passed +task_id+
2951
# For more information on how to build the query please refer to the
3052
# Elasticsearch DSL documentation:
@@ -38,9 +60,17 @@ def initialize(client:)
3860
# query fails.
3961
def by_id(task_id)
4062
retry_request do
41-
transport_client.tasks.get(task_id:, wait_for_completion: true).deep_symbolize_keys
63+
tasks_client.get(task_id:, wait_for_completion: true).deep_symbolize_keys
4264
end
4365
end
66+
67+
private
68+
69+
# @return [Elasticsearch::API::Tasks::TasksClient] The client used to
70+
# access tasks-related information.
71+
def tasks_client
72+
@tasks_client ||= transport_client.tasks
73+
end
4474
end
4575
end
4676
end

spec/jay_api/elasticsearch/tasks_spec.rb

Lines changed: 160 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3,12 +3,13 @@
33
require 'jay_api/elasticsearch/tasks'
44

55
RSpec.describe JayAPI::Elasticsearch::Tasks do
6-
subject(:tasks) { described_class.new(client: client) }
6+
subject(:tasks) { described_class.new(client:) }
77

88
let(:tasks_client) do
99
instance_double(
1010
Elasticsearch::API::Tasks::TasksClient,
11-
get: transport_response
11+
get: transport_response,
12+
list: transport_response
1213
)
1314
end
1415

@@ -29,6 +30,162 @@
2930
)
3031
end
3132

33+
shared_examples_for '#tasks_client' do
34+
it 'gets the Transport::Client from the given Client' do
35+
expect(client).to receive(:transport_client).ordered
36+
expect(transport_client).to receive(:tasks).ordered
37+
method_call
38+
end
39+
end
40+
41+
describe '#all' do
42+
subject(:method_call) { tasks.all(**method_params) }
43+
44+
let(:method_params) { {} }
45+
46+
let(:transport_response) do
47+
{ 'nodes' =>
48+
{ 'S13zyUneSa2Brl5XRNoD7Q' =>
49+
{ 'name' => 'c8f5b1ae733a17bf05b35c66032e72e7',
50+
'roles' => %w[data ingest master remote_cluster_client],
51+
'tasks' =>
52+
{ 'S13zyUneSa2Brl5XRNoD7Q:170466185' =>
53+
{ 'node' => 'S13zyUneSa2Brl5XRNoD7Q',
54+
'id' => 170_466_185,
55+
'type' => 'direct',
56+
'action' => 'cluster:monitor/tasks/lists[n]',
57+
'start_time_in_millis' => 1_773_072_735_568,
58+
'running_time_in_nanos' => 13_000_011,
59+
'cancellable' => false,
60+
'cancelled' => false,
61+
'parent_task_id' => 'S13zyUneSa2Brl5XRNoD7Q:170466184',
62+
'headers' => {} },
63+
'S13zyUneSa2Brl5XRNoD7Q:170466184' =>
64+
{ 'node' => 'S13zyUneSa2Brl5XRNoD7Q',
65+
'id' => 170_466_184,
66+
'type' => 'transport',
67+
'action' => 'cluster:monitor/tasks/lists',
68+
'start_time_in_millis' => 1_773_072_735_557,
69+
'running_time_in_nanos' => 29_102_229,
70+
'cancellable' => false,
71+
'cancelled' => false,
72+
'headers' => {} } } },
73+
'2MqUhOT_Sdi6ZJ8P04aUtg' =>
74+
{ 'name' => '224b01c103d31d5f520636719d930944',
75+
'roles' => %w[data ingest master remote_cluster_client],
76+
'tasks' =>
77+
{ '2MqUhOT_Sdi6ZJ8P04aUtg:80324869' =>
78+
{ 'node' => '2MqUhOT_Sdi6ZJ8P04aUtg',
79+
'id' => 80_324_869,
80+
'type' => 'transport',
81+
'action' => 'cluster:monitor/tasks/lists[n]',
82+
'start_time_in_millis' => 1_773_072_735_582,
83+
'running_time_in_nanos' => 23_474_179,
84+
'cancellable' => false,
85+
'cancelled' => false,
86+
'parent_task_id' => 'S13zyUneSa2Brl5XRNoD7Q:170466184',
87+
'headers' => {} } } } } }
88+
end
89+
90+
shared_examples_for '#all' do
91+
it 'directly returns the response' do
92+
expect(method_call).to be(transport_response)
93+
end
94+
end
95+
96+
shared_examples_for '#all when no parameters are given' do
97+
it_behaves_like '#tasks_client'
98+
99+
it 'forwards the call to the Elasticsearch client, with the expected parameter' do
100+
expect(tasks_client).to receive(:list).with({})
101+
method_call
102+
end
103+
104+
it_behaves_like '#all'
105+
end
106+
107+
context 'when no parameters are given' do
108+
let(:method_params) { {} }
109+
110+
it_behaves_like '#all when no parameters are given'
111+
end
112+
113+
context 'when actions are provided as a single string' do
114+
let(:method_params) { { actions: '*forcemerge' } }
115+
116+
it_behaves_like '#tasks_client'
117+
118+
it 'forwards the call to the Elasticsearch client, with the expected parameters' do
119+
expect(tasks_client).to receive(:list).with({ actions: '*forcemerge' })
120+
method_call
121+
end
122+
123+
it_behaves_like '#all'
124+
end
125+
126+
context 'when actions are provided as an array of strings' do
127+
let(:method_params) { { actions: %w[*forcemerge *byquery] } }
128+
129+
it_behaves_like '#tasks_client'
130+
131+
it 'forwards the call to the Elasticsearch client, with the expected parameters' do
132+
expect(tasks_client).to receive(:list).with({ actions: '*forcemerge,*byquery' })
133+
method_call
134+
end
135+
136+
it_behaves_like '#all'
137+
end
138+
139+
context 'when no tasks match the given actions' do
140+
let(:method_params) { { actions: %w[*ingest] } }
141+
142+
let(:transport_response) do
143+
{ 'nodes' => {} }
144+
end
145+
146+
it_behaves_like '#tasks_client'
147+
148+
it 'forwards the call to the Elasticsearch client, with the expected parameters' do
149+
expect(tasks_client).to receive(:list).with({ actions: '*ingest' })
150+
method_call
151+
end
152+
153+
it_behaves_like '#all'
154+
end
155+
156+
context "when 'detailed' is given as false" do
157+
let(:method_params) { { detailed: false } }
158+
159+
it_behaves_like '#all when no parameters are given'
160+
end
161+
162+
context "when 'detailed' is given as true" do
163+
let(:method_params) { { detailed: true } }
164+
165+
it_behaves_like '#tasks_client'
166+
167+
it 'forwards the call to the Elasticsearch client, with the expected parameters' do
168+
expect(tasks_client).to receive(:list).with({ detailed: true })
169+
method_call
170+
end
171+
172+
it_behaves_like '#all'
173+
end
174+
175+
context "when both 'actions' and 'detailed' are given" do
176+
let(:method_params) { { actions: '*forcemerge', detailed: true } }
177+
178+
it_behaves_like '#tasks_client'
179+
180+
it 'forwards the call to the Elasticsearch client, with the expected parameters' do
181+
expect(tasks_client).to receive(:list).with({ actions: '*forcemerge', detailed: true })
182+
method_call
183+
end
184+
185+
it_behaves_like '#all'
186+
end
187+
end
188+
32189
describe '#by_id' do
33190
subject(:method_call) { tasks.by_id(task_id) }
34191

@@ -94,11 +251,7 @@
94251
}
95252
end
96253

97-
it 'gets the Transport::Client from the given Client' do
98-
expect(client).to receive(:transport_client).ordered
99-
expect(transport_client).to receive(:tasks).ordered
100-
method_call
101-
end
254+
it_behaves_like '#tasks_client'
102255

103256
it 'uses the TasksClient to fetch the task with the given ID' do
104257
expect(tasks_client).to receive(:get).with(task_id:, wait_for_completion: true).ordered

0 commit comments

Comments
 (0)