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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +10 -0
  3. data/Gemfile +2 -1
  4. data/Gemfile.lock +18 -12
  5. data/README.md +50 -41
  6. data/lib/esse/async_indexing/actions/{batch_delete.rb → bulk_delete.rb} +2 -2
  7. data/lib/esse/async_indexing/actions/{batch_import.rb → bulk_import.rb} +1 -1
  8. data/lib/esse/async_indexing/actions/{batch_import_all.rb → bulk_import_all.rb} +1 -1
  9. data/lib/esse/async_indexing/actions/{batch_update.rb → bulk_update.rb} +6 -4
  10. data/lib/esse/async_indexing/actions/{update_lazy_document_attribute.rb → bulk_update_lazy_attribute.rb} +1 -1
  11. data/lib/esse/async_indexing/actions/delete_document.rb +1 -1
  12. data/lib/esse/async_indexing/actions/index_document.rb +1 -1
  13. data/lib/esse/async_indexing/actions/update_document.rb +1 -1
  14. data/lib/esse/async_indexing/actions/upsert_document.rb +1 -2
  15. data/lib/esse/async_indexing/actions.rb +5 -7
  16. data/lib/esse/async_indexing/active_record_callbacks/lazy_update_attribute.rb +8 -5
  17. data/lib/esse/async_indexing/cli/async_import.rb +27 -18
  18. data/lib/esse/async_indexing/cli/async_update_lazy_attributes.rb +78 -0
  19. data/lib/esse/async_indexing/cli.rb +23 -9
  20. data/lib/esse/async_indexing/config.rb +0 -3
  21. data/lib/esse/async_indexing/configuration.rb +54 -18
  22. data/lib/esse/async_indexing/jobs/bulk_update_lazy_attribute_job.rb +7 -0
  23. data/lib/esse/async_indexing/jobs/import_all_job.rb +1 -1
  24. data/lib/esse/async_indexing/jobs/import_ids_job.rb +42 -0
  25. data/lib/esse/async_indexing/{workers.rb → jobs.rb} +7 -24
  26. data/lib/esse/async_indexing/tasks.rb +82 -0
  27. data/lib/esse/async_indexing/version.rb +1 -1
  28. data/lib/esse/async_indexing.rb +15 -20
  29. data/lib/esse/plugins/async_indexing.rb +18 -59
  30. metadata +19 -32
  31. data/lib/esse/async_indexing/actions/bulk_update_lazy_document_attribute.rb +0 -20
  32. data/lib/esse/async_indexing/actions/import_batch_id.rb +0 -21
  33. data/lib/esse/async_indexing/adapters/adapter.rb +0 -29
  34. data/lib/esse/async_indexing/adapters/faktory.rb +0 -114
  35. data/lib/esse/async_indexing/adapters/sidekiq.rb +0 -94
  36. data/lib/esse/async_indexing/adapters.rb +0 -12
  37. data/lib/esse/async_indexing/configuration/base.rb +0 -65
  38. data/lib/esse/async_indexing/configuration/faktory.rb +0 -6
  39. data/lib/esse/async_indexing/configuration/sidekiq.rb +0 -12
  40. data/lib/esse/async_indexing/jobs/bulk_update_lazy_document_attribute_job.rb +0 -7
  41. data/lib/esse/async_indexing/jobs/import_batch_id_job.rb +0 -34
  42. data/lib/esse/async_indexing/jobs/update_lazy_document_attribute_job.rb +0 -7
  43. data/lib/esse/async_indexing/testing.rb +0 -79
  44. data/lib/esse/async_indexing/worker.rb +0 -85
  45. data/lib/esse/async_indexing/workers/faktory.rb +0 -28
  46. data/lib/esse/async_indexing/workers/shared_class_methods.rb +0 -26
  47. 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: a7931a646008cb93875d4e0fc47a552c2a19e3f9089c5e500e3cbb822f32f9bd
4
- data.tar.gz: 374d59d804ca1b37e30f853b765d5b6ea0b975a97335d45249fa6e9f019d171c
3
+ metadata.gz: 50b00ff520d7e52425dd2b97ff0ce4cf7f3f7c2bd8275ef2a36d290e9ca3165e
4
+ data.tar.gz: 5ad4d7445414dcc7c9cc670fa348ee26d4cd589aa71e9c84a331ce7d848e43b1
5
5
  SHA512:
6
- metadata.gz: fb5ef232b141e0b2ee7f629f139376f4ef169da0b7078fdf6b5e74937219c096f065e5d0b982004ab0fe50b0b5363fd09dad62a1fab110f59d84d0e7f7072561
7
- data.tar.gz: 7b09c24955e14df91435ef2a4ce39796c36ddb7ee0e9c173a40fbad0e7d11cf86c67b891454555f5814ebaf56994042a361de7c2fbd9ab093a7709a946aed0c2
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.2)
5
- esse (>= 0.3.4)
6
- esse-redis_storage (>= 0.1.0)
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.2.0)
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
- esse
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
- Optional worker configuration:
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.workers = {
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: 3 },
53
- "Esse::AsyncIndexing::Jobs::ImportBatchIdJob" => { queue: "batch_indexing", retry: 3 },
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.workers = {
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: 3 },
64
- "Esse::AsyncIndexing::Jobs::ImportBatchIdJob" => { queue: "batch_indexing", retry: 3 },
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 worker does not need to live in the same application that enqueues the job. The worker can be in a separate application that only runs the worker process. This gem has its own DSL to push jobs.
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 worker application by calling `install!`
132
+ But for make sure to require the jobs in the job application by calling `install!`
113
133
 
114
134
  ```ruby
115
- Esse::AsyncIndexing::Workers.install!(:faktory)
116
- Esse::AsyncIndexing::Workers.install!(:sidekiq)
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
- Esse::AsyncIndexing.worker("Esse::AsyncIndexing::Jobs::DocumentIndexByIdJob", service: :sidekiq).with_args("GeosIndex", "city", city.id, suffix: "20240101")
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
- Esse::AsyncIndexing.worker("Esse::AsyncIndexing::Jobs::DocumentUpdateByIdJob", service: :sidekiq).with_args("GeosIndex", "city", city.id, suffix: "20240101")
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
- Esse::AsyncIndexing.worker("Esse::AsyncIndexing::Jobs::DocumentUpsertByIdJob", service: :sidekiq).with_args("GeosIndex", "city", city.id, suffix: "20240101")
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
- Esse::AsyncIndexing.worker("Esse::AsyncIndexing::Jobs::DocumentDeleteByIdJob", service: :sidekiq).with_args("GeosIndex", "city", city.id, suffix: "20240101")
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
- Esse::AsyncIndexing.worker("Esse::AsyncIndexing::Jobs::ImportAllJob", service: :sidekiq).with_args("GeosIndex", "city", context: {state_abbr: "IL"}, suffix: "20240101")
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::ImportBatchIdJob
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
- Update a lazy attribute of a document from the index using the given enqueued batch_id.
194
+ Import a batch of documents from the `GeosIndex.repo(:city)` collection using the given ids
185
195
 
186
196
  ```ruby
187
- batch_id = Esse::RedisStorage::Queue.for(repo: GeosIndex.repo(:city), attribute_name: "total_schools").enqueue(values: big_list_of_uuids)
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::UpdateLazyDocumentAttributeJob
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
- Esse::AsyncIndexing.worker("Esse::AsyncIndexing::Jobs::UpdateLazyDocumentAttributeJob", service: :sidekiq).with_args("GeosIndex", "city", "total_schools", [city.id], suffix: "20240101")
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 BatchDelete
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(&:to_doc))
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 BatchImport
4
+ class BulkImport
5
5
  def self.call(index_class_name, repo_name, ids, options = {})
6
6
  ids = Array(ids)
7
7
  return if ids.empty?
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Esse::AsyncIndexing::Actions
4
- class BatchImportAll
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 BatchUpdate
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 (lazy_attributes = bulk_opts.delete(:lazy_attributes))
18
- find_opts[:lazy_attributes] = lazy_attributes
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 UpdateLazyDocumentAttribute
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[lazy_attributes]
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[lazy_attributes]
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[lazy_attributes]
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[lazy_attributes]
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/batch_import_all"
12
- require_relative "actions/batch_import"
13
- require_relative "actions/batch_delete"
14
- require_relative "actions/batch_update"
15
- require_relative "actions/bulk_update_lazy_document_attribute"
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
- Esse::AsyncIndexing.worker(LAZY_ATTR_WORKER, service: service_name)
18
- .with_args(repo.index.name, repo.repo_name, attribute_name.to_s, doc_ids, Esse::HashUtils.deep_transform_keys(options, &:to_s))
19
- .push
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::ImportBatchIdJob"
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 you have the `plugin :async_indexing` in your `#{index}` class and the :#{repo.repo_name} collection implements the `#each_batch_ids` method.
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
- enqueuer = if (caller = repo.async_indexing_jobs[:import])
25
- ->(ids) { caller.call(service_name, repo, :import, ids, **bulk_options) }
26
- else
27
- queue = Esse::RedisStorage::Queue.for(repo: repo)
28
- ->(ids) do
29
- batch_id = queue.enqueue(values: ids)
30
- Esse::AsyncIndexing.worker(WORKER_NAME, service: service_name)
31
- .with_args(repo.index.name, repo.repo_name, batch_id, Esse::HashUtils.deep_transform_keys(bulk_options, &:to_s))
32
- .push
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, :service])
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