esse-async_indexing 0.0.2 → 0.1.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +10 -0
- data/Gemfile +2 -1
- data/Gemfile.lock +18 -12
- data/README.md +50 -41
- data/lib/esse/async_indexing/actions/{batch_delete.rb → bulk_delete.rb} +2 -2
- data/lib/esse/async_indexing/actions/{batch_import.rb → bulk_import.rb} +1 -1
- data/lib/esse/async_indexing/actions/{batch_import_all.rb → bulk_import_all.rb} +1 -1
- data/lib/esse/async_indexing/actions/{batch_update.rb → bulk_update.rb} +6 -4
- data/lib/esse/async_indexing/actions/{update_lazy_document_attribute.rb → bulk_update_lazy_attribute.rb} +1 -1
- data/lib/esse/async_indexing/actions/delete_document.rb +1 -1
- data/lib/esse/async_indexing/actions/index_document.rb +1 -1
- data/lib/esse/async_indexing/actions/update_document.rb +1 -1
- data/lib/esse/async_indexing/actions/upsert_document.rb +1 -2
- data/lib/esse/async_indexing/actions.rb +5 -7
- data/lib/esse/async_indexing/active_record_callbacks/lazy_update_attribute.rb +8 -5
- data/lib/esse/async_indexing/cli/async_import.rb +27 -18
- data/lib/esse/async_indexing/cli/async_update_lazy_attributes.rb +78 -0
- data/lib/esse/async_indexing/cli.rb +23 -9
- data/lib/esse/async_indexing/config.rb +0 -3
- data/lib/esse/async_indexing/configuration.rb +54 -18
- data/lib/esse/async_indexing/jobs/bulk_update_lazy_attribute_job.rb +7 -0
- data/lib/esse/async_indexing/jobs/import_all_job.rb +1 -1
- data/lib/esse/async_indexing/jobs/import_ids_job.rb +42 -0
- data/lib/esse/async_indexing/{workers.rb → jobs.rb} +7 -24
- data/lib/esse/async_indexing/tasks.rb +82 -0
- data/lib/esse/async_indexing/version.rb +1 -1
- data/lib/esse/async_indexing.rb +15 -20
- data/lib/esse/plugins/async_indexing.rb +18 -59
- metadata +19 -32
- data/lib/esse/async_indexing/actions/bulk_update_lazy_document_attribute.rb +0 -20
- data/lib/esse/async_indexing/actions/import_batch_id.rb +0 -21
- data/lib/esse/async_indexing/adapters/adapter.rb +0 -29
- data/lib/esse/async_indexing/adapters/faktory.rb +0 -114
- data/lib/esse/async_indexing/adapters/sidekiq.rb +0 -94
- data/lib/esse/async_indexing/adapters.rb +0 -12
- data/lib/esse/async_indexing/configuration/base.rb +0 -65
- data/lib/esse/async_indexing/configuration/faktory.rb +0 -6
- data/lib/esse/async_indexing/configuration/sidekiq.rb +0 -12
- data/lib/esse/async_indexing/jobs/bulk_update_lazy_document_attribute_job.rb +0 -7
- data/lib/esse/async_indexing/jobs/import_batch_id_job.rb +0 -34
- data/lib/esse/async_indexing/jobs/update_lazy_document_attribute_job.rb +0 -7
- data/lib/esse/async_indexing/testing.rb +0 -79
- data/lib/esse/async_indexing/worker.rb +0 -85
- data/lib/esse/async_indexing/workers/faktory.rb +0 -28
- data/lib/esse/async_indexing/workers/shared_class_methods.rb +0 -26
- data/lib/esse/async_indexing/workers/sidekiq.rb +0 -28
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 50b00ff520d7e52425dd2b97ff0ce4cf7f3f7c2bd8275ef2a36d290e9ca3165e
|
4
|
+
data.tar.gz: 5ad4d7445414dcc7c9cc670fa348ee26d4cd589aa71e9c84a331ce7d848e43b1
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 20b7b5d815774e36d237d2273442546fa5289d45b4db187962c48da4e2f153219d1cc2439cb2461c75cdaff5b6ff0ceb8e27eacfe3c754f908a22300431c80f9
|
7
|
+
data.tar.gz: 538588ff73ce223fbfbfb46e19d7b47ee8da1131734f0e6228ff0142adf13324ade2f31b94209538e94e8b8fffa85b28ef9644dbc71f8dcb1874410046da8659
|
data/CHANGELOG.md
CHANGED
@@ -4,6 +4,16 @@ All notable changes to this project will be documented in this file.
|
|
4
4
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
6
6
|
|
7
|
+
## 0.1.0 - 2024-08-22
|
8
|
+
* Remove esse-redis_storage dependency
|
9
|
+
* Remove the batch id jobs and actions related redis storage
|
10
|
+
* Add the --eager-load-lazy-attributes option to the async_import cli command
|
11
|
+
* Add the --update-lazy-attributes option to the async_import cli command
|
12
|
+
* Add the --enqueue-lazy-attributes option to the async_import cli command
|
13
|
+
* Add the --preload-lazy-attributes option to the async_import cli command
|
14
|
+
* Add the --job-options option to the async_import cli command
|
15
|
+
* Update import related jobs to process ids instead of batch id
|
16
|
+
|
7
17
|
## 0.0.2 - 2024-08-02
|
8
18
|
* Include sidekiq and faktory jobs to perform async indexing of documents
|
9
19
|
* Create Active Model async indexing callbacks
|
data/Gemfile
CHANGED
@@ -2,11 +2,12 @@
|
|
2
2
|
|
3
3
|
source "https://rubygems.org"
|
4
4
|
|
5
|
-
gem "esse"
|
5
|
+
gem "esse", github: "marcosgz/esse", branch: "main"
|
6
6
|
gem "esse-rspec"
|
7
7
|
gem "esse-active_record", ">= 0.3.5", require: false
|
8
8
|
gem "timecop"
|
9
9
|
gem "faktory_worker_ruby", require: false
|
10
10
|
gem "opensearch-ruby", require: false
|
11
|
+
gem "background_job"
|
11
12
|
|
12
13
|
gemspec
|
data/Gemfile.lock
CHANGED
@@ -1,9 +1,18 @@
|
|
1
|
+
GIT
|
2
|
+
remote: https://github.com/marcosgz/esse.git
|
3
|
+
revision: 8fd302274e9c9c0dcdeec7b8f6ffafc05234014b
|
4
|
+
branch: main
|
5
|
+
specs:
|
6
|
+
esse (0.4.0.rc1)
|
7
|
+
multi_json
|
8
|
+
thor (>= 0.19)
|
9
|
+
|
1
10
|
PATH
|
2
11
|
remote: .
|
3
12
|
specs:
|
4
|
-
esse-async_indexing (0.0.
|
5
|
-
|
6
|
-
esse
|
13
|
+
esse-async_indexing (0.1.0.rc1)
|
14
|
+
background_job
|
15
|
+
esse (>= 0.4.0.rc01)
|
7
16
|
multi_json
|
8
17
|
|
9
18
|
GEM
|
@@ -28,6 +37,9 @@ GEM
|
|
28
37
|
addressable (2.8.7)
|
29
38
|
public_suffix (>= 2.0.2, < 7.0)
|
30
39
|
ast (2.4.2)
|
40
|
+
background_job (0.0.1.rc3)
|
41
|
+
multi_json
|
42
|
+
redis
|
31
43
|
base64 (0.2.0)
|
32
44
|
bigdecimal (3.1.8)
|
33
45
|
coderay (1.1.3)
|
@@ -38,16 +50,9 @@ GEM
|
|
38
50
|
rexml
|
39
51
|
diff-lcs (1.5.1)
|
40
52
|
drb (2.2.1)
|
41
|
-
esse (0.3.4)
|
42
|
-
multi_json
|
43
|
-
thor (>= 0.19)
|
44
53
|
esse-active_record (0.3.5)
|
45
54
|
activerecord (>= 4.2, < 8)
|
46
55
|
esse (>= 0.3.0)
|
47
|
-
esse-redis_storage (0.1.0)
|
48
|
-
esse (>= 0.3.2)
|
49
|
-
multi_json (>= 1.0.0)
|
50
|
-
redis (>= 4.0.0)
|
51
56
|
esse-rspec (0.0.6)
|
52
57
|
esse (>= 0.2.4)
|
53
58
|
rspec (>= 3)
|
@@ -81,7 +86,7 @@ GEM
|
|
81
86
|
public_suffix (5.1.1)
|
82
87
|
racc (1.8.0)
|
83
88
|
rainbow (3.1.1)
|
84
|
-
redis (5.
|
89
|
+
redis (5.3.0)
|
85
90
|
redis-client (>= 0.22.0)
|
86
91
|
redis-client (0.22.2)
|
87
92
|
connection_pool
|
@@ -149,7 +154,8 @@ PLATFORMS
|
|
149
154
|
x86_64-linux
|
150
155
|
|
151
156
|
DEPENDENCIES
|
152
|
-
|
157
|
+
background_job
|
158
|
+
esse!
|
153
159
|
esse-active_record (>= 0.3.5)
|
154
160
|
esse-async_indexing!
|
155
161
|
esse-rspec
|
data/README.md
CHANGED
@@ -21,17 +21,13 @@ $ bundle install
|
|
21
21
|
|
22
22
|
```ruby
|
23
23
|
Esse.configure do |config|
|
24
|
-
config.redis = ConnectionPool.new(size: 10, timeout: 5) do
|
25
|
-
Redis.new(url: ENV.fetch('REDIS_URL', 'redis://0.0.0.0:6379'))
|
26
|
-
end
|
27
|
-
|
28
24
|
# Setup Sidekiq
|
29
25
|
require 'sidekiq'
|
30
26
|
config.async_indexing.sidekiq do |sidekiq|
|
31
|
-
sidekiq.namespace = "sidekiq"
|
32
27
|
sidekiq.redis = ConnectionPool.new(size: 10, timeout: 5) do
|
33
28
|
Redis.new(url: ENV.fetch('REDIS_URL', 'redis://0.0.0.0:6379'))
|
34
29
|
end
|
30
|
+
# sidekiq.namespace = "sidekiq" # Sidekiq recommends using redis db number instead of namespace, but you can use it if you want
|
35
31
|
end
|
36
32
|
|
37
33
|
# Faktory
|
@@ -40,34 +36,58 @@ Esse.configure do |config|
|
|
40
36
|
end
|
41
37
|
```
|
42
38
|
|
43
|
-
|
39
|
+
### Configuration > Jobs Queues
|
40
|
+
|
41
|
+
Set the queues for each job and other options like retry, timeout, etc:
|
44
42
|
|
45
43
|
```ruby
|
46
44
|
Esse.configure do |config|
|
47
|
-
config.async_indexing.sidekiq.
|
45
|
+
config.async_indexing.sidekiq.jobs = {
|
46
|
+
"Esse::AsyncIndexing::Jobs::BulkUpdateLazyAttributeJob" => { queue: "batch_indexing" },
|
48
47
|
"Esse::AsyncIndexing::Jobs::DocumentDeleteByIdJob" => { queue: "indexing" },
|
49
48
|
"Esse::AsyncIndexing::Jobs::DocumentIndexByIdJob" => { queue: "indexing" },
|
50
49
|
"Esse::AsyncIndexing::Jobs::DocumentUpdateByIdJob" => { queue: "indexing" },
|
51
50
|
"Esse::AsyncIndexing::Jobs::DocumentUpsertByIdJob" => { queue: "indexing" },
|
52
|
-
"Esse::AsyncIndexing::Jobs::ImportAllJob" => { queue: "batch_indexing", retry:
|
53
|
-
"Esse::AsyncIndexing::Jobs::
|
54
|
-
"Esse::AsyncIndexing::Jobs::BulkUpdateLazyDocumentAttributeJob" => { queue: "batch_indexing", retry: 3 },
|
55
|
-
"Esse::AsyncIndexing::Jobs::UpdateLazyDocumentAttributeJob" => { queue: "indexing" },
|
51
|
+
"Esse::AsyncIndexing::Jobs::ImportAllJob" => { queue: "batch_indexing", retry: false },
|
52
|
+
"Esse::AsyncIndexing::Jobs::ImportIdsJob" => { queue: "batch_indexing", retry: 2 },
|
56
53
|
}
|
57
54
|
# or if you are using Faktory
|
58
|
-
config.async_indexing.faktory.
|
55
|
+
config.async_indexing.faktory.jobs = {
|
56
|
+
"Esse::AsyncIndexing::Jobs::BulkUpdateLazyAttributeJob" => { queue: "batch_indexing" },
|
59
57
|
"Esse::AsyncIndexing::Jobs::DocumentDeleteByIdJob" => { queue: "indexing" },
|
60
58
|
"Esse::AsyncIndexing::Jobs::DocumentIndexByIdJob" => { queue: "indexing" },
|
61
59
|
"Esse::AsyncIndexing::Jobs::DocumentUpdateByIdJob" => { queue: "indexing" },
|
62
60
|
"Esse::AsyncIndexing::Jobs::DocumentUpsertByIdJob" => { queue: "indexing" },
|
63
|
-
"Esse::AsyncIndexing::Jobs::ImportAllJob" => { queue: "batch_indexing", retry:
|
64
|
-
"Esse::AsyncIndexing::Jobs::
|
65
|
-
"Esse::AsyncIndexing::Jobs::BulkUpdateLazyDocumentAttributeJob" => { queue: "batch_indexing", retry: 3 },
|
66
|
-
"Esse::AsyncIndexing::Jobs::UpdateLazyDocumentAttributeJob" => { queue: "indexing" },
|
61
|
+
"Esse::AsyncIndexing::Jobs::ImportAllJob" => { queue: "batch_indexing", retry: false },
|
62
|
+
"Esse::AsyncIndexing::Jobs::ImportIdsJob" => { queue: "batch_indexing", retry: 2 },
|
67
63
|
}
|
68
64
|
end
|
69
65
|
```
|
70
66
|
|
67
|
+
### Configuration > Tasks
|
68
|
+
|
69
|
+
To overwrite the default job that is enqueued for each operation. The default jobs are:
|
70
|
+
* :import => Esse::AsyncIndexing::Jobs::ImportIdsJob
|
71
|
+
* :index => Esse::AsyncIndexing::Jobs::DocumentIndexByIdJob
|
72
|
+
* :update => Esse::AsyncIndexing::Jobs::DocumentUpdateByIdJob
|
73
|
+
* :delete => Esse::AsyncIndexing::Jobs::DocumentDeleteByIdJob
|
74
|
+
* :update_lazy_attribute => Esse::AsyncIndexing::Jobs::BulkUpdateLazyAttributeJob
|
75
|
+
|
76
|
+
The operation can be set globally using the `task` method or per index using the `async_indexing_job` method.
|
77
|
+
|
78
|
+
Example above will first store ids in different storage and just enqueue job with the batch_id:
|
79
|
+
|
80
|
+
```ruby
|
81
|
+
Esse.configure do |config|
|
82
|
+
config.async_indexing.task(:import) do |service:, repo:, operation:, ids:, **kwargs|
|
83
|
+
batch_id = Esse::RedisStorage::Queue.for(repo: repo).enqueue(values: ids)
|
84
|
+
ImportBatchIdJob.perform_later(repo.index.name, repo.repo_name, batch_id, **kwargs)
|
85
|
+
end
|
86
|
+
end
|
87
|
+
```
|
88
|
+
|
89
|
+
Now when calling the async_import CLI command, it will push jobs to the `ImportBatchIdJob` instead of the standard `Esse::AsyncIndexing::Jobs::ImportIdsJob`.
|
90
|
+
|
71
91
|
## Index Configuration
|
72
92
|
|
73
93
|
To enable async indexing for an index, you need to add the `:async_indexing` plugin to the index. And the index collection must implement the `#each_batch_ids` method that yields an array of document ids.
|
@@ -107,13 +127,13 @@ $ bundle exec esse index async_import GeosIndex --suffix="20240101" --service="s
|
|
107
127
|
|
108
128
|
## Workers/Jobs
|
109
129
|
|
110
|
-
The gem provides a few jobs to index, update, upsert and delete document or batch of documents with given ids. The sidekiq or faktory
|
130
|
+
The gem provides a few jobs to index, update, upsert and delete document or batch of documents with given ids. The sidekiq or faktory job does not need to live in the same application that enqueues the job. The job can be in a separate application that only runs the job process. This gem has its own DSL to push jobs.
|
111
131
|
|
112
|
-
But for make sure to require the jobs in the
|
132
|
+
But for make sure to require the jobs in the job application by calling `install!`
|
113
133
|
|
114
134
|
```ruby
|
115
|
-
Esse::AsyncIndexing::
|
116
|
-
Esse::AsyncIndexing::
|
135
|
+
Esse::AsyncIndexing::Jobs.install!(:faktory)
|
136
|
+
Esse::AsyncIndexing::Jobs.install!(:sidekiq)
|
117
137
|
```
|
118
138
|
|
119
139
|
|
@@ -122,7 +142,7 @@ Esse::AsyncIndexing::Workers.install!(:sidekiq)
|
|
122
142
|
Fetch a document from `GeosIndex.repo(:city)` collection using the given id and index it
|
123
143
|
|
124
144
|
```ruby
|
125
|
-
|
145
|
+
BackgroundJob.sidekiq("Esse::AsyncIndexing::Jobs::DocumentIndexByIdJob").with_args("GeosIndex", "city", city.id, "suffix" => "20240101")
|
126
146
|
.push
|
127
147
|
```
|
128
148
|
|
@@ -133,7 +153,7 @@ Esse::AsyncIndexing.worker("Esse::AsyncIndexing::Jobs::DocumentIndexByIdJob", se
|
|
133
153
|
Fetch a document from `GeosIndex.repo(:city)` collection using the given id and update it
|
134
154
|
|
135
155
|
```ruby
|
136
|
-
|
156
|
+
BackgroundJob.sidekiq("Esse::AsyncIndexing::Jobs::DocumentUpdateByIdJob").with_args("GeosIndex", "city", city.id, "suffix" => "20240101")
|
137
157
|
```
|
138
158
|
|
139
159
|
**Note:** Suffix is optional, just an example of how to pass additional arguments to the job.
|
@@ -143,7 +163,7 @@ Esse::AsyncIndexing.worker("Esse::AsyncIndexing::Jobs::DocumentUpdateByIdJob", s
|
|
143
163
|
Fetch a document from `GeosIndex.repo(:city)` collection using the given id and upsert it
|
144
164
|
|
145
165
|
```ruby
|
146
|
-
|
166
|
+
BackgroundJob.sidekiq("Esse::AsyncIndexing::Jobs::DocumentUpsertByIdJob").with_args("GeosIndex", "city", city.id, "suffix" => "20240101")
|
147
167
|
```
|
148
168
|
|
149
169
|
**Note:** Suffix is optional, just an example of how to pass additional arguments to the job.
|
@@ -154,7 +174,7 @@ Esse::AsyncIndexing.worker("Esse::AsyncIndexing::Jobs::DocumentUpsertByIdJob", s
|
|
154
174
|
Delete a document from the index using the given id
|
155
175
|
|
156
176
|
```ruby
|
157
|
-
|
177
|
+
BackgroundJob.sidekiq("Esse::AsyncIndexing::Jobs::DocumentDeleteByIdJob").with_args("GeosIndex", "city", city.id, "suffix" => "20240101")
|
158
178
|
```
|
159
179
|
|
160
180
|
**Note:** Suffix is optional, just an example of how to pass additional arguments to the job.
|
@@ -164,38 +184,27 @@ Esse::AsyncIndexing.worker("Esse::AsyncIndexing::Jobs::DocumentDeleteByIdJob", s
|
|
164
184
|
Import all documents from the `GeosIndex.repo(:city)` collection where `state_abbr` is "IL"
|
165
185
|
|
166
186
|
```ruby
|
167
|
-
|
187
|
+
BackgroundJob.sidekiq("Esse::AsyncIndexing::Jobs::ImportAllJob").with_args("GeosIndex", "city", "context" => { "state_abbr" => "IL"}, "suffix" => "20240101")
|
168
188
|
```
|
169
189
|
|
170
190
|
**Note:** Suffix and import context are optional, just an example of how to pass additional arguments to the job.
|
171
191
|
|
172
|
-
### Esse::AsyncIndexing::Jobs::
|
173
|
-
|
174
|
-
Import a batch of documents from the `GeosIndex.repo(:city)` collection using a batch_id generated by the [esse-redis_storage](https://github.com/marcosgz/esse-redis_storage) gem. This is the job that the `async_import` command uses.
|
175
|
-
|
176
|
-
```ruby
|
177
|
-
batch_id = Esse::RedisStorage::Queue.for(repo: GeosIndex.repo(:city)).enqueue(values: big_list_of_uuids)
|
178
|
-
Esse::AsyncIndexing.worker("Esse::AsyncIndexing::Jobs::ImportBatchIdJob", service: :sidekiq).with_args("GeosIndex", "city", batch_id, suffix: "20240101")
|
179
|
-
```
|
180
|
-
**Note:** Suffix is optional, just an example of how to pass additional arguments to the job.
|
181
|
-
|
182
|
-
### Esse::AsyncIndexing::Jobs::BulkUpdateLazyDocumentAttributeJob
|
192
|
+
### Esse::AsyncIndexing::Jobs::ImportIdsJob
|
183
193
|
|
184
|
-
|
194
|
+
Import a batch of documents from the `GeosIndex.repo(:city)` collection using the given ids
|
185
195
|
|
186
196
|
```ruby
|
187
|
-
|
188
|
-
Esse::AsyncIndexing.worker("Esse::AsyncIndexing::Jobs::BulkUpdateLazyDocumentAttributeJob", service: :sidekiq).with_args("GeosIndex", "city", "total_schools", batch_id, suffix: "20240101")
|
197
|
+
BackgroundJob.sidekiq("Esse::AsyncIndexing::Jobs::ImportIdsJob").with_args("GeosIndex", "city", city_ids, "suffix" => "20240101")
|
189
198
|
```
|
190
199
|
|
191
200
|
**Note:** Suffix is optional, just an example of how to pass additional arguments to the job.
|
192
201
|
|
193
|
-
### Esse::AsyncIndexing::Jobs::
|
202
|
+
### Esse::AsyncIndexing::Jobs::BulkUpdateLazyAttributeJob
|
194
203
|
|
195
204
|
Update a lazy attribute of a document from the index using the given id
|
196
205
|
|
197
206
|
```ruby
|
198
|
-
|
207
|
+
BackgroundJob.sidekiq("Esse::AsyncIndexing::Jobs::BulkUpdateLazyAttributeJob").with_args("GeosIndex", "city", "total_schools", [city.id], "suffix" => "20240101")
|
199
208
|
```
|
200
209
|
|
201
210
|
**Note:** Suffix is optional, just an example of how to pass additional arguments to the job.
|
@@ -1,14 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Esse::AsyncIndexing::Actions
|
4
|
-
class
|
4
|
+
class BulkDelete
|
5
5
|
def self.call(index_class_name, repo_name, ids, options = {})
|
6
6
|
docs = Esse::LazyDocumentHeader.coerce_each(ids)
|
7
7
|
return if docs.empty?
|
8
8
|
|
9
9
|
index_class, _repo_class = CoerceIndexRepository.call(index_class_name, repo_name)
|
10
10
|
bulk_opts = Esse::HashUtils.deep_transform_keys(options, &:to_sym)
|
11
|
-
index_class.bulk(**bulk_opts, delete: docs.map(&:
|
11
|
+
index_class.bulk(**bulk_opts, delete: docs.map(&:doc_header))
|
12
12
|
docs.size
|
13
13
|
end
|
14
14
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Esse::AsyncIndexing::Actions
|
4
|
-
class
|
4
|
+
class BulkImportAll
|
5
5
|
def self.call(index_class_name, repo_name, options = {})
|
6
6
|
_index_class, repo_class = CoerceIndexRepository.call(index_class_name, repo_name)
|
7
7
|
kwargs = Esse::HashUtils.deep_transform_keys(options, &:to_sym)
|
@@ -1,8 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Esse::AsyncIndexing::Actions
|
4
|
-
class
|
5
|
-
DOC_ARGS = %i[lazy_attributes context]
|
4
|
+
class BulkUpdate
|
6
5
|
|
7
6
|
def self.call(index_class_name, repo_name, ids, options = {})
|
8
7
|
ids = Array(ids)
|
@@ -14,8 +13,11 @@ module Esse::AsyncIndexing::Actions
|
|
14
13
|
if (context = bulk_opts.delete(:context))
|
15
14
|
find_opts.merge!(context)
|
16
15
|
end
|
17
|
-
if (
|
18
|
-
find_opts[:
|
16
|
+
if (val = bulk_opts.delete(:eager_load_lazy_attributes))
|
17
|
+
find_opts[:eager_load_lazy_attributes] = val
|
18
|
+
end
|
19
|
+
if (val = bulk_opts.delete(:preload_lazy_attributes))
|
20
|
+
find_opts[:preload_lazy_attributes] = val
|
19
21
|
end
|
20
22
|
find_opts[:id] = ids
|
21
23
|
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Esse::AsyncIndexing::Actions
|
4
|
-
class
|
4
|
+
class BulkUpdateLazyAttribute
|
5
5
|
def self.call(index_class_name, repo_name, attr_name, ids, options = {})
|
6
6
|
_index_class, repo_class = CoerceIndexRepository.call(index_class_name, repo_name)
|
7
7
|
kwargs = Esse::HashUtils.deep_transform_keys(options, &:to_sym)
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Esse::AsyncIndexing::Actions
|
4
4
|
class DeleteDocument
|
5
|
-
DOC_ARGS = %i[
|
5
|
+
DOC_ARGS = %i[eager_load_lazy_attributes preload_lazy_attributes]
|
6
6
|
|
7
7
|
def self.call(index_class_name, repo_name, document_id, options = {})
|
8
8
|
index_class, _repo_class = CoerceIndexRepository.call(index_class_name, repo_name)
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Esse::AsyncIndexing::Actions
|
4
4
|
class IndexDocument
|
5
|
-
DOC_ARGS = %i[
|
5
|
+
DOC_ARGS = %i[eager_load_lazy_attributes preload_lazy_attributes]
|
6
6
|
|
7
7
|
def self.call(index_class_name, repo_name, document_id, options = {})
|
8
8
|
index_class, repo_class = CoerceIndexRepository.call(index_class_name, repo_name)
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module Esse::AsyncIndexing::Actions
|
4
4
|
class UpdateDocument
|
5
|
-
DOC_ARGS = %i[
|
5
|
+
DOC_ARGS = %i[eager_load_lazy_attributes preload_lazy_attributes]
|
6
6
|
|
7
7
|
def self.call(index_class_name, repo_name, document_id, options = {})
|
8
8
|
index_class, repo_class = CoerceIndexRepository.call(index_class_name, repo_name)
|
@@ -2,8 +2,7 @@
|
|
2
2
|
|
3
3
|
module Esse::AsyncIndexing::Actions
|
4
4
|
class UpsertDocument
|
5
|
-
DOC_ARGS = %i[
|
6
|
-
# OPERATIONS = %w[index update delete]
|
5
|
+
DOC_ARGS = %i[eager_load_lazy_attributes preload_lazy_attributes]
|
7
6
|
|
8
7
|
def self.call(index_class_name, repo_name, document_id, operation = "index", options = {})
|
9
8
|
case operation
|
@@ -8,14 +8,12 @@ module Esse
|
|
8
8
|
end
|
9
9
|
|
10
10
|
require_relative "actions/coerce_index_repository"
|
11
|
-
require_relative "actions/
|
12
|
-
require_relative "actions/
|
13
|
-
require_relative "actions/
|
14
|
-
require_relative "actions/
|
15
|
-
require_relative "actions/
|
11
|
+
require_relative "actions/bulk_delete"
|
12
|
+
require_relative "actions/bulk_import_all"
|
13
|
+
require_relative "actions/bulk_import"
|
14
|
+
require_relative "actions/bulk_update_lazy_attribute"
|
15
|
+
require_relative "actions/bulk_update"
|
16
16
|
require_relative "actions/delete_document"
|
17
|
-
require_relative "actions/import_batch_id"
|
18
17
|
require_relative "actions/index_document"
|
19
18
|
require_relative "actions/update_document"
|
20
19
|
require_relative "actions/upsert_document"
|
21
|
-
require_relative "actions/update_lazy_document_attribute"
|
@@ -3,8 +3,6 @@
|
|
3
3
|
module Esse::AsyncIndexing
|
4
4
|
module ActiveRecordCallbacks
|
5
5
|
class LazyUpdateAttribute < Callback
|
6
|
-
LAZY_ATTR_WORKER = "Esse::AsyncIndexing::Jobs::UpdateLazyDocumentAttributeJob"
|
7
|
-
|
8
6
|
attr_reader :attribute_name
|
9
7
|
|
10
8
|
def initialize(service_name:, attribute_name:, with: nil, **kwargs)
|
@@ -14,9 +12,14 @@ module Esse::AsyncIndexing
|
|
14
12
|
|
15
13
|
def call(model)
|
16
14
|
if (doc_ids = resolve_document_ids(model))
|
17
|
-
|
18
|
-
|
19
|
-
|
15
|
+
repo.async_indexing_job_for(:update_lazy_attribute).call(
|
16
|
+
service: service_name,
|
17
|
+
repo: repo,
|
18
|
+
operation: :update_lazy_attribute,
|
19
|
+
attribute: attribute_name,
|
20
|
+
ids: doc_ids,
|
21
|
+
**options
|
22
|
+
)
|
20
23
|
end
|
21
24
|
|
22
25
|
true
|
@@ -3,11 +3,25 @@
|
|
3
3
|
require "esse/cli/index/base_operation"
|
4
4
|
|
5
5
|
class Esse::AsyncIndexing::CLI::AsyncImport < Esse::CLI::Index::BaseOperation
|
6
|
-
WORKER_NAME = "Esse::AsyncIndexing::Jobs::
|
6
|
+
WORKER_NAME = "Esse::AsyncIndexing::Jobs::ImportIdsJob"
|
7
|
+
|
8
|
+
attr_reader :job_options, :service_name
|
9
|
+
|
10
|
+
def initialize(indices:, job_options: {}, service: nil, **options)
|
11
|
+
@job_options = job_options
|
12
|
+
@service_name = (service || Esse.config.async_indexing.services.first)&.to_sym
|
13
|
+
super(indices: indices, **options)
|
14
|
+
end
|
7
15
|
|
8
16
|
def run
|
9
17
|
validate_options!
|
10
18
|
indices.each do |index|
|
19
|
+
unless Esse::AsyncIndexing.plugin_installed?(index)
|
20
|
+
raise Esse::CLI::InvalidOption, <<~MSG
|
21
|
+
The #{index} index does not support async indexing. Make sure you have the `plugin :async_indexing` in your `#{index}` class.
|
22
|
+
MSG
|
23
|
+
end
|
24
|
+
|
11
25
|
repos = if (repo = @options[:repo])
|
12
26
|
[index.repo(repo)]
|
13
27
|
else
|
@@ -17,23 +31,22 @@ class Esse::AsyncIndexing::CLI::AsyncImport < Esse::CLI::Index::BaseOperation
|
|
17
31
|
repos.each do |repo|
|
18
32
|
unless Esse::AsyncIndexing.async_indexing_repo?(repo)
|
19
33
|
raise Esse::CLI::InvalidOption, <<~MSG
|
20
|
-
The #{repo} repository does not support async indexing. Make sure
|
34
|
+
The #{repo} repository does not support async indexing. Make sure the :#{repo.repo_name} collection of `#{index}` implements the `#each_batch_ids` method.
|
21
35
|
MSG
|
22
36
|
end
|
23
37
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
38
|
+
repo.batch_ids(**bulk_options.fetch(:context, {})).each do |ids|
|
39
|
+
kwargs = {
|
40
|
+
service: service_name,
|
41
|
+
repo: repo,
|
42
|
+
operation: :import,
|
43
|
+
ids: ids,
|
44
|
+
**bulk_options
|
45
|
+
}.tap do |hash|
|
46
|
+
hash[:job_options] = job_options if job_options.any?
|
33
47
|
end
|
48
|
+
repo.async_indexing_job_for(:import).call(**kwargs)
|
34
49
|
end
|
35
|
-
|
36
|
-
repo.batch_ids.each(&enqueuer)
|
37
50
|
end
|
38
51
|
end
|
39
52
|
end
|
@@ -42,7 +55,7 @@ class Esse::AsyncIndexing::CLI::AsyncImport < Esse::CLI::Index::BaseOperation
|
|
42
55
|
|
43
56
|
def bulk_options
|
44
57
|
@bulk_options ||= begin
|
45
|
-
hash = @options.slice(*@options.keys - Esse::CLI_IGNORE_OPTS - [:repo
|
58
|
+
hash = @options.slice(*@options.keys - Esse::CLI_IGNORE_OPTS - [:repo])
|
46
59
|
hash.delete(:context) if hash[:context].nil? || hash[:context].empty?
|
47
60
|
hash
|
48
61
|
end
|
@@ -51,8 +64,4 @@ class Esse::AsyncIndexing::CLI::AsyncImport < Esse::CLI::Index::BaseOperation
|
|
51
64
|
def validate_options!
|
52
65
|
validate_indices_option!
|
53
66
|
end
|
54
|
-
|
55
|
-
def service_name
|
56
|
-
(@options[:service] || Esse.config.async_indexing.services.first)&.to_sym
|
57
|
-
end
|
58
67
|
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "esse/cli/index/base_operation"
|
4
|
+
|
5
|
+
class Esse::AsyncIndexing::CLI::AsyncUpdateLazyAttributes < Esse::CLI::Index::BaseOperation
|
6
|
+
WORKER_NAME = "Esse::AsyncIndexing::Jobs::BulkUpdateLazyAttributeJob"
|
7
|
+
|
8
|
+
attr_reader :attributes, :job_options, :service_name
|
9
|
+
|
10
|
+
def initialize(indices:, attributes: nil, job_options: nil, service: nil, **options)
|
11
|
+
super(indices: indices, **options)
|
12
|
+
@attributes = Array(attributes)
|
13
|
+
@job_options = job_options || {}
|
14
|
+
@service_name = (service || Esse.config.async_indexing.services.first)&.to_sym
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
validate_options!
|
19
|
+
indices.each do |index|
|
20
|
+
unless Esse::AsyncIndexing.plugin_installed?(index)
|
21
|
+
raise Esse::CLI::InvalidOption, <<~MSG
|
22
|
+
The #{index} index does not support async indexing. Make sure you have the `plugin :async_indexing` in your `#{index}` class.
|
23
|
+
MSG
|
24
|
+
end
|
25
|
+
|
26
|
+
repos = if (repo = @options[:repo])
|
27
|
+
[index.repo(repo)]
|
28
|
+
else
|
29
|
+
index.repo_hash.values
|
30
|
+
end
|
31
|
+
|
32
|
+
repos.each do |repo|
|
33
|
+
unless Esse::AsyncIndexing.async_indexing_repo?(repo)
|
34
|
+
raise Esse::CLI::InvalidOption, <<~MSG
|
35
|
+
The #{repo} repository does not support async indexing. Make sure the :#{repo.repo_name} collection of `#{index}` implements the `#each_batch_ids` method.
|
36
|
+
MSG
|
37
|
+
end
|
38
|
+
|
39
|
+
attrs = repo_attributes(repo)
|
40
|
+
next unless attrs.any?
|
41
|
+
|
42
|
+
repo.batch_ids(**@options.fetch(:context, {})).each do |ids|
|
43
|
+
kwargs = {
|
44
|
+
service: service_name,
|
45
|
+
repo: repo,
|
46
|
+
operation: :update_lazy_attribute,
|
47
|
+
ids: ids,
|
48
|
+
**bulk_options
|
49
|
+
}.tap do |hash|
|
50
|
+
hash[:job_options] = job_options if job_options.any?
|
51
|
+
end
|
52
|
+
attrs.each do |attribute|
|
53
|
+
repo.async_indexing_job_for(:update_lazy_attribute).call(**kwargs, attribute: attribute)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def bulk_options
|
63
|
+
@bulk_options ||= begin
|
64
|
+
hash = @options.slice(*@options.keys - Esse::CLI_IGNORE_OPTS - [:context, :repo])
|
65
|
+
hash
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def validate_options!
|
70
|
+
validate_indices_option!
|
71
|
+
end
|
72
|
+
|
73
|
+
def repo_attributes(repo)
|
74
|
+
return repo.lazy_document_attributes.keys if attributes.empty?
|
75
|
+
|
76
|
+
repo.lazy_document_attribute_names(attributes)
|
77
|
+
end
|
78
|
+
end
|