esse-async_indexing 0.0.2 → 0.1.0.rc2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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/bulk_update_lazy_attribute.rb +19 -0
- 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/actions/update_lazy_document_attribute.rb +0 -14
- 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
@@ -1,20 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Esse::AsyncIndexing::Actions
|
4
|
-
class BulkUpdateLazyDocumentAttribute
|
5
|
-
def self.call(index_class_name, repo_name, attr_name, batch_id, options = {})
|
6
|
-
_index_class, repo_class = CoerceIndexRepository.call(index_class_name, repo_name)
|
7
|
-
queue = Esse::RedisStorage::Queue.for(repo: repo_class, attribute_name: attr_name)
|
8
|
-
|
9
|
-
kwargs = Esse::HashUtils.deep_transform_keys(options, &:to_sym)
|
10
|
-
|
11
|
-
attr_name = repo_class.lazy_document_attributes.keys.find { |key| key.to_s == attr_name.to_s }
|
12
|
-
updated_ids = []
|
13
|
-
queue.fetch(batch_id) do |ids|
|
14
|
-
updated_ids = ids
|
15
|
-
repo_class.update_documents_attribute(attr_name, ids, **kwargs)
|
16
|
-
end
|
17
|
-
updated_ids
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,21 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Esse::AsyncIndexing::Actions
|
4
|
-
class ImportBatchId
|
5
|
-
def self.call(index_class_name, repo_name, batch_id, options = {})
|
6
|
-
_index_class, repo_class = CoerceIndexRepository.call(index_class_name, repo_name)
|
7
|
-
queue = Esse::RedisStorage::Queue.for(repo: repo_class)
|
8
|
-
|
9
|
-
kwargs = Esse::HashUtils.deep_transform_keys(options, &:to_sym)
|
10
|
-
kwargs[:context] ||= {}
|
11
|
-
result = 0
|
12
|
-
ids_from_batch = []
|
13
|
-
queue.fetch(batch_id) do |ids|
|
14
|
-
ids_from_batch = ids
|
15
|
-
kwargs[:context][:id] = ids
|
16
|
-
result = repo_class.import(**kwargs)
|
17
|
-
end
|
18
|
-
[result, ids_from_batch]
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
@@ -1,14 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Esse::AsyncIndexing::Actions
|
4
|
-
class UpdateLazyDocumentAttribute
|
5
|
-
def self.call(index_class_name, repo_name, attr_name, ids, options = {})
|
6
|
-
_index_class, repo_class = CoerceIndexRepository.call(index_class_name, repo_name)
|
7
|
-
kwargs = Esse::HashUtils.deep_transform_keys(options, &:to_sym)
|
8
|
-
|
9
|
-
attr_name = repo_class.lazy_document_attributes.keys.find { |key| key.to_s == attr_name.to_s }
|
10
|
-
repo_class.update_documents_attribute(attr_name, ids, **kwargs)
|
11
|
-
ids
|
12
|
-
end
|
13
|
-
end
|
14
|
-
end
|
@@ -1,29 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Esse::AsyncIndexing
|
4
|
-
module Adapters
|
5
|
-
class Adapter
|
6
|
-
# Push the worker job to the service
|
7
|
-
# @param _worker [Esse::AsyncIndexing::Worker] An instance of background worker
|
8
|
-
# @abstract Child classes should override this method
|
9
|
-
def self.push(_worker)
|
10
|
-
raise NotImplemented
|
11
|
-
end
|
12
|
-
|
13
|
-
# Coerces the raw payload into an instance of Worker
|
14
|
-
# @param payload [Object] the object that should be coerced to a Worker
|
15
|
-
# @options options [Hash] list of options that will be passed along to the Worker instance
|
16
|
-
# @return [Esse::AsyncIndexing::Worker] and instance of Esse::AsyncIndexing::Worker
|
17
|
-
# @abstract Child classes should override this method
|
18
|
-
def self.coerce_to_worker(payload, **options)
|
19
|
-
raise NotImplemented
|
20
|
-
end
|
21
|
-
|
22
|
-
protected
|
23
|
-
|
24
|
-
def normalize_before_push
|
25
|
-
# noop
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
@@ -1,114 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Esse::AsyncIndexing
|
4
|
-
module Adapters
|
5
|
-
# This is a Faktory adapter that converts Esse::AsyncIndexing::Worker object into a faktory readable format
|
6
|
-
# and then push the jobs into the service.
|
7
|
-
class Faktory < Adapter
|
8
|
-
attr_reader :worker, :queue
|
9
|
-
|
10
|
-
def initialize(worker)
|
11
|
-
@worker = worker
|
12
|
-
@queue = worker.options.fetch(:queue, "default")
|
13
|
-
|
14
|
-
@payload = worker.payload.merge(
|
15
|
-
"jobtype" => worker.worker_class,
|
16
|
-
"queue" => @queue,
|
17
|
-
"retry" => parse_retry(worker.options[:retry])
|
18
|
-
)
|
19
|
-
@payload["created_at"] ||= Time.now.to_f
|
20
|
-
end
|
21
|
-
|
22
|
-
# Coerces the raw payload into an instance of Worker
|
23
|
-
# @param payload [Hash] The job as json from redis
|
24
|
-
# @options options [Hash] list of options that will be passed along to the Worker instance
|
25
|
-
# @return [Esse::AsyncIndexing::Worker] and instance of Esse::AsyncIndexing::Worker
|
26
|
-
def self.coerce_to_worker(payload, **options)
|
27
|
-
raise(Error, "invalid payload") unless payload.is_a?(Hash)
|
28
|
-
raise(Error, "invalid payload") unless payload["jobtype"].is_a?(String)
|
29
|
-
|
30
|
-
options[:retry] ||= payload["retry"] if payload.key?("retry")
|
31
|
-
options[:queue] ||= payload["queue"] if payload.key?("queue")
|
32
|
-
|
33
|
-
Esse::AsyncIndexing.worker(payload["jobtype"], **options, service: :faktory).tap do |worker|
|
34
|
-
worker.with_args(*Array(payload["args"])) if payload.key?("args")
|
35
|
-
worker.with_job_jid(payload["jid"]) if payload.key?("jid")
|
36
|
-
worker.created_at(payload["created_at"]) if payload.key?("created_at")
|
37
|
-
worker.enqueued_at(payload["enqueued_at"]) if payload.key?("enqueued_at")
|
38
|
-
worker.at(payload["at"]) if payload.key?("at")
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
# Initializes adapter and push job into the faktory service
|
43
|
-
#
|
44
|
-
# @param worker [Esse::AsyncIndexing::Worker] An instance of Esse::AsyncIndexing::Worker
|
45
|
-
# @return [Hash] Job payload
|
46
|
-
# @see push method for more details
|
47
|
-
def self.push(worker)
|
48
|
-
new(worker).push
|
49
|
-
end
|
50
|
-
|
51
|
-
# Push job to Faktory
|
52
|
-
# * If job has the 'at' key. Then schedule it
|
53
|
-
# * Otherwise enqueue for immediate execution
|
54
|
-
#
|
55
|
-
# @raise [Esse::AsyncIndexing::Error] raise and error when faktory dependency is not loaded
|
56
|
-
# @return [Hash] Payload that was sent to server
|
57
|
-
def push
|
58
|
-
unless Object.const_defined?(:Faktory)
|
59
|
-
raise Esse::AsyncIndexing::Error, <<~ERR
|
60
|
-
Faktory client for ruby is not loaded. You must install and require https://github.com/contribsys/faktory_worker_ruby.
|
61
|
-
ERR
|
62
|
-
end
|
63
|
-
normalize_before_push
|
64
|
-
|
65
|
-
pool = Thread.current[:faktory_via_pool] || ::Faktory.server_pool
|
66
|
-
::Faktory.client_middleware.invoke(@payload, pool) do
|
67
|
-
pool.with do |c|
|
68
|
-
c.push(@payload)
|
69
|
-
end
|
70
|
-
end
|
71
|
-
@payload
|
72
|
-
end
|
73
|
-
|
74
|
-
protected
|
75
|
-
|
76
|
-
# Convert worker retry value acording to the Go struct datatype.
|
77
|
-
#
|
78
|
-
# * 25 is the default.
|
79
|
-
# * 0 means the job is completely ephemeral. No matter if it fails or succeeds, it will be discarded.
|
80
|
-
# * -1 means the job will go straight to the Dead set if it fails, no retries.
|
81
|
-
def parse_retry(value)
|
82
|
-
case value
|
83
|
-
when Numeric then value.to_i
|
84
|
-
when false then -1
|
85
|
-
else
|
86
|
-
25
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def parse_time(value)
|
91
|
-
case value
|
92
|
-
when Numeric then Time.at(value).to_datetime.rfc3339(9)
|
93
|
-
when Time then value.to_datetime.rfc3339(9)
|
94
|
-
when DateTime then value.rfc3339(9)
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def to_json(value)
|
99
|
-
MultiJson.dump(value, mode: :compat)
|
100
|
-
end
|
101
|
-
|
102
|
-
def normalize_before_push
|
103
|
-
@payload["enqueued_at"] ||= Time.now.to_f
|
104
|
-
{"created_at" => false, "enqueued_at" => false, "at" => true}.each do |field, past_remove|
|
105
|
-
# Optimization to enqueue something now that is scheduled to go out now or in the past
|
106
|
-
if (time = @payload.delete(field)) &&
|
107
|
-
(!past_remove || (past_remove && time > Time.now.to_f))
|
108
|
-
@payload[field] = parse_time(time)
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|
@@ -1,94 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Esse::AsyncIndexing
|
4
|
-
module Adapters
|
5
|
-
# This is a Sidekiq adapter that converts Esse::AsyncIndexing::Worker object into a sidekiq readable format
|
6
|
-
# and then push the jobs into the service.
|
7
|
-
class Sidekiq < Adapter
|
8
|
-
attr_reader :worker, :queue
|
9
|
-
|
10
|
-
def initialize(worker)
|
11
|
-
@worker = worker
|
12
|
-
@queue = worker.options.fetch(:queue, "default")
|
13
|
-
|
14
|
-
@payload = worker.payload.merge(
|
15
|
-
"class" => worker.worker_class,
|
16
|
-
"retry" => worker.options.fetch(:retry, true),
|
17
|
-
"queue" => @queue
|
18
|
-
)
|
19
|
-
@payload["created_at"] ||= Time.now.to_f
|
20
|
-
end
|
21
|
-
|
22
|
-
# Coerces the raw payload into an instance of Worker
|
23
|
-
# @param payload [Hash] The job as json from redis
|
24
|
-
# @options options [Hash] list of options that will be passed along to the Worker instance
|
25
|
-
# @return [Esse::AsyncIndexing::Worker] and instance of Esse::AsyncIndexing::Worker
|
26
|
-
def self.coerce_to_worker(payload, **options)
|
27
|
-
raise(Error, "invalid payload") unless payload.is_a?(Hash)
|
28
|
-
raise(Error, "invalid payload") unless payload["class"].is_a?(String)
|
29
|
-
|
30
|
-
options[:retry] ||= payload["retry"] if payload.key?("retry")
|
31
|
-
options[:queue] ||= payload["queue"] if payload.key?("queue")
|
32
|
-
|
33
|
-
Esse::AsyncIndexing.worker(payload["class"], **options, service: :sidekiq).tap do |worker|
|
34
|
-
worker.with_args(*Array(payload["args"])) if payload.key?("args")
|
35
|
-
worker.with_job_jid(payload["jid"]) if payload.key?("jid")
|
36
|
-
worker.created_at(payload["created_at"]) if payload.key?("created_at")
|
37
|
-
worker.enqueued_at(payload["enqueued_at"]) if payload.key?("enqueued_at")
|
38
|
-
worker.at(payload["at"]) if payload.key?("at")
|
39
|
-
end
|
40
|
-
end
|
41
|
-
|
42
|
-
# Initializes adapter and push job into the sidekiq service
|
43
|
-
#
|
44
|
-
# @param worker [Esse::AsyncIndexing::Worker] An instance of Esse::AsyncIndexing::Worker
|
45
|
-
# @return [Hash] Job payload
|
46
|
-
# @see push method for more details
|
47
|
-
def self.push(worker)
|
48
|
-
new(worker).push
|
49
|
-
end
|
50
|
-
|
51
|
-
# Push sidekiq to the Sidekiq(Redis actually).
|
52
|
-
# * If job has the 'at' key. Then schedule it
|
53
|
-
# * Otherwise enqueue for immediate execution
|
54
|
-
#
|
55
|
-
# @return [Hash] Payload that was sent to redis
|
56
|
-
def push
|
57
|
-
normalize_before_push
|
58
|
-
# Optimization to enqueue something now that is scheduled to go out now or in the past
|
59
|
-
if (timestamp = @payload.delete("at")) && (timestamp > Time.now.to_f)
|
60
|
-
Esse.config.async_indexing.sidekiq.redis_pool.with do |redis|
|
61
|
-
redis.zadd(scheduled_queue_name, timestamp.to_f.to_s, to_json(@payload))
|
62
|
-
end
|
63
|
-
else
|
64
|
-
Esse.config.async_indexing.sidekiq.redis_pool.with do |redis|
|
65
|
-
redis.lpush(immediate_queue_name, to_json(@payload))
|
66
|
-
end
|
67
|
-
end
|
68
|
-
@payload
|
69
|
-
end
|
70
|
-
|
71
|
-
protected
|
72
|
-
|
73
|
-
def namespace
|
74
|
-
Esse.config.async_indexing.sidekiq.namespace
|
75
|
-
end
|
76
|
-
|
77
|
-
def scheduled_queue_name
|
78
|
-
"#{namespace}:schedule"
|
79
|
-
end
|
80
|
-
|
81
|
-
def immediate_queue_name
|
82
|
-
"#{namespace}:queue:#{queue}"
|
83
|
-
end
|
84
|
-
|
85
|
-
def to_json(value)
|
86
|
-
MultiJson.dump(value, mode: :compat)
|
87
|
-
end
|
88
|
-
|
89
|
-
def normalize_before_push
|
90
|
-
@payload["enqueued_at"] = Time.now.to_f
|
91
|
-
end
|
92
|
-
end
|
93
|
-
end
|
94
|
-
end
|
@@ -1,65 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class Esse::AsyncIndexing::Configuration::Base
|
4
|
-
class << self
|
5
|
-
private
|
6
|
-
|
7
|
-
def attribute_accessor(field, validator: nil, normalizer: nil, default: nil)
|
8
|
-
normalizer ||= :"normalize_#{field}"
|
9
|
-
validator ||= :"validate_#{field}"
|
10
|
-
|
11
|
-
define_method(field) do
|
12
|
-
unless instance_variable_defined?(:"@#{field}")
|
13
|
-
return if default.nil?
|
14
|
-
|
15
|
-
send(:"#{field}=", default.respond_to?(:call) ? default.call : default)
|
16
|
-
end
|
17
|
-
instance_variable_get(:"@#{field}")
|
18
|
-
end
|
19
|
-
|
20
|
-
define_method(:"#{field}=") do |value|
|
21
|
-
value = send(normalizer, field, value) if respond_to?(normalizer, true)
|
22
|
-
send(validator, field, value) if respond_to?(validator, true)
|
23
|
-
|
24
|
-
instance_variable_set(:"@#{field}", value)
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
# A Hash with all workers definitions. The worker class name must be the main hash key
|
30
|
-
# Example:
|
31
|
-
# "FaktoryIndexWorker":
|
32
|
-
# retry: false
|
33
|
-
# queue: "indexing"
|
34
|
-
# adapter: "faktory"
|
35
|
-
# "FaktoryBatchIndexWorker":
|
36
|
-
# retry: 5
|
37
|
-
# queue: "batch_index"
|
38
|
-
# adapter: "faktory"
|
39
|
-
attribute_accessor :workers, default: {}
|
40
|
-
|
41
|
-
def worker_options(class_name)
|
42
|
-
class_name = class_name.to_s
|
43
|
-
if strict? && !workers.key?(class_name)
|
44
|
-
raise Esse::AsyncIndexing::NotDefinedWorkerError.new(class_name)
|
45
|
-
end
|
46
|
-
|
47
|
-
workers.fetch(class_name, {})
|
48
|
-
end
|
49
|
-
|
50
|
-
def strict?
|
51
|
-
true
|
52
|
-
end
|
53
|
-
|
54
|
-
protected
|
55
|
-
|
56
|
-
def normalize_workers(_, value)
|
57
|
-
return unless value.is_a?(Hash)
|
58
|
-
|
59
|
-
hash = Esse::AsyncIndexing::Workers::DEFAULT.values.map { |v| [v, {}] }.to_h
|
60
|
-
value.each do |class_name, opts|
|
61
|
-
hash[class_name.to_s] = Esse::HashUtils.deep_transform_keys(opts.to_h, &:to_sym)
|
62
|
-
end
|
63
|
-
hash
|
64
|
-
end
|
65
|
-
end
|
@@ -1,12 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Esse::AsyncIndexing
|
4
|
-
class Configuration::Sidekiq < Configuration::Base
|
5
|
-
attribute_accessor :redis
|
6
|
-
attribute_accessor :namespace, default: "sidekiq"
|
7
|
-
|
8
|
-
def redis_pool
|
9
|
-
@redis_pool ||= Esse::RedisStorage::Pool.new(redis)
|
10
|
-
end
|
11
|
-
end
|
12
|
-
end
|
@@ -1,7 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class Esse::AsyncIndexing::Jobs::BulkUpdateLazyDocumentAttributeJob
|
4
|
-
def perform(index_class_name, repo_name, attribute_name, batch_id, options = {})
|
5
|
-
Esse::AsyncIndexing::Actions::BulkUpdateLazyDocumentAttribute.call(index_class_name, repo_name, attribute_name, batch_id, options)
|
6
|
-
end
|
7
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class Esse::AsyncIndexing::Jobs::ImportBatchIdJob
|
4
|
-
LAZY_ATTR_WORKER = "Esse::AsyncIndexing::Jobs::BulkUpdateLazyDocumentAttributeJob"
|
5
|
-
|
6
|
-
def perform(index_class_name, repo_name, batch_id, options = {})
|
7
|
-
total, ids = Esse::AsyncIndexing::Actions::ImportBatchId.call(index_class_name, repo_name, batch_id, options)
|
8
|
-
|
9
|
-
options = Esse::HashUtils.deep_transform_keys(options, &:to_s)
|
10
|
-
return total if total.zero?
|
11
|
-
return total if lazy_already_imported?(options)
|
12
|
-
return total unless self.class.respond_to?(:bg_worker_options)
|
13
|
-
|
14
|
-
_index_class, repo_class = Esse::AsyncIndexing::Actions::CoerceIndexRepository.call(index_class_name, repo_name)
|
15
|
-
|
16
|
-
repo_class.lazy_document_attributes.each_key do |attr_name|
|
17
|
-
queue = Esse::RedisStorage::Queue.for(repo: repo_class, attribute_name: attr_name)
|
18
|
-
queue.enqueue(id: batch_id, values: ids)
|
19
|
-
Esse::AsyncIndexing.worker(LAZY_ATTR_WORKER, service: self.class.bg_worker_options[:service])
|
20
|
-
.with_args(index_class_name, repo_name, attr_name.to_s, batch_id, options)
|
21
|
-
.push
|
22
|
-
end
|
23
|
-
total
|
24
|
-
end
|
25
|
-
|
26
|
-
protected
|
27
|
-
|
28
|
-
# The `import` action already eager or lazy load the document attributes when some of these options are set.
|
29
|
-
def lazy_already_imported?(options)
|
30
|
-
eager = options.delete("eager_include_document_attributes") || false
|
31
|
-
lazy = options.delete("lazy_update_document_attributes") || false
|
32
|
-
eager || lazy
|
33
|
-
end
|
34
|
-
end
|
@@ -1,7 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
class Esse::AsyncIndexing::Jobs::UpdateLazyDocumentAttributeJob
|
4
|
-
def perform(index_class_name, repo_name, attribute_name, ids, options = {})
|
5
|
-
Esse::AsyncIndexing::Actions::UpdateLazyDocumentAttribute.call(index_class_name, repo_name, attribute_name, ids, options)
|
6
|
-
end
|
7
|
-
end
|
@@ -1,79 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Esse
|
4
|
-
module AsyncIndexing
|
5
|
-
class Testing
|
6
|
-
class << self
|
7
|
-
def enable!
|
8
|
-
Thread.current[:esse_async_indexing_testing] = true
|
9
|
-
end
|
10
|
-
|
11
|
-
def disable!
|
12
|
-
Thread.current[:esse_async_indexing_testing] = false
|
13
|
-
end
|
14
|
-
|
15
|
-
def enabled?
|
16
|
-
Thread.current[:esse_async_indexing_testing] == true
|
17
|
-
end
|
18
|
-
|
19
|
-
def disabled?
|
20
|
-
!enabled?
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
Esse::AsyncIndexing::Testing.disable!
|
28
|
-
|
29
|
-
module Esse::AsyncIndexing::Jobs
|
30
|
-
class << self
|
31
|
-
def jobs
|
32
|
-
@jobs ||= []
|
33
|
-
end
|
34
|
-
|
35
|
-
def push(job)
|
36
|
-
jobs.push(job)
|
37
|
-
end
|
38
|
-
|
39
|
-
def clear
|
40
|
-
jobs.clear
|
41
|
-
end
|
42
|
-
|
43
|
-
def size
|
44
|
-
jobs.size
|
45
|
-
end
|
46
|
-
|
47
|
-
def jobs_for(service: nil, class_name: nil)
|
48
|
-
filtered = jobs
|
49
|
-
if service
|
50
|
-
filtered = filtered.select { |job| job["service"] == service.to_s }
|
51
|
-
end
|
52
|
-
if class_name
|
53
|
-
filtered = filtered.select { |job| job["__class_name__"] == class_name.to_s }
|
54
|
-
end
|
55
|
-
filtered
|
56
|
-
end
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
module Esse::AsyncIndexing::JobsInterceptorAdapter
|
61
|
-
def push
|
62
|
-
return super unless Esse::AsyncIndexing::Testing.enabled?
|
63
|
-
|
64
|
-
normalize_before_push
|
65
|
-
test_payload = @payload.dup
|
66
|
-
if @payload["jobtype"]
|
67
|
-
test_payload["service"] = "faktory"
|
68
|
-
test_payload["__class_name__"] = @payload["jobtype"]
|
69
|
-
else
|
70
|
-
test_payload["service"] = "sidekiq"
|
71
|
-
test_payload["__class_name__"] = @payload["class"]
|
72
|
-
end
|
73
|
-
Esse::AsyncIndexing::Jobs.push(test_payload)
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
Esse::AsyncIndexing::SERVICES.each_value do |adapter|
|
78
|
-
adapter.prepend(Esse::AsyncIndexing::JobsInterceptorAdapter)
|
79
|
-
end
|
@@ -1,85 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Esse::AsyncIndexing
|
4
|
-
class Worker
|
5
|
-
attr_reader :options, :payload, :worker_class, :service
|
6
|
-
|
7
|
-
attr_reader :arguments
|
8
|
-
|
9
|
-
def initialize(worker_class, service: nil, **options)
|
10
|
-
@worker_class = worker_class
|
11
|
-
@service = service
|
12
|
-
@options = options
|
13
|
-
@payload = {}
|
14
|
-
end
|
15
|
-
|
16
|
-
def self.coerce(service:, payload:, **opts)
|
17
|
-
Esse::AsyncIndexing::SERVICES.fetch(service).coerce_to_worker(payload, **opts)
|
18
|
-
end
|
19
|
-
|
20
|
-
%i[created_at enqueued_at].each do |method_name|
|
21
|
-
define_method method_name do |value|
|
22
|
-
@payload[method_name.to_s] =
|
23
|
-
case value
|
24
|
-
when Numeric then value.to_f
|
25
|
-
when String then Time.parse(value).to_f
|
26
|
-
when Time, DateTime then value.to_f
|
27
|
-
else
|
28
|
-
raise ArgumentError, format("The %<v>p is not a valid value for %<m>s.", v: value, m: method_name)
|
29
|
-
end
|
30
|
-
|
31
|
-
self
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
# Adds arguments to the job
|
36
|
-
# @return self
|
37
|
-
def with_args(*args)
|
38
|
-
@payload["args"] = args
|
39
|
-
|
40
|
-
self
|
41
|
-
end
|
42
|
-
|
43
|
-
# Schedule the time when a job will be executed. Jobs which are scheduled in the past are enqueued for immediate execution.
|
44
|
-
# @param timestamp [Numeric] timestamp, numeric or something that acts numeric.
|
45
|
-
# @return self
|
46
|
-
def in(timestamp)
|
47
|
-
now = Time.now.to_f
|
48
|
-
timestamp = Time.parse(timestamp) if timestamp.is_a?(String)
|
49
|
-
int = timestamp.respond_to?(:strftime) ? timestamp.to_f : now + timestamp.to_f
|
50
|
-
return self if int <= now
|
51
|
-
|
52
|
-
@payload["at"] = int
|
53
|
-
@payload["created_at"] = now
|
54
|
-
|
55
|
-
self
|
56
|
-
end
|
57
|
-
alias_method :at, :in
|
58
|
-
|
59
|
-
def with_job_jid(jid = nil)
|
60
|
-
@payload["jid"] ||= jid || Esse::AsyncIndexing.jid
|
61
|
-
|
62
|
-
self
|
63
|
-
end
|
64
|
-
|
65
|
-
# @return Response of service
|
66
|
-
# @see Esse::AsyncIndexing::Adapters::** for more details
|
67
|
-
def push
|
68
|
-
unless Esse::AsyncIndexing::SERVICES.key?(service)
|
69
|
-
raise Esse::AsyncIndexing::Error, format("Service %<service>p is not implemented. Please use one of #{Esse::AsyncIndexing::SERVICES.keys.map(&:inspect).join(" or ")}.", service: service)
|
70
|
-
end
|
71
|
-
@payload["created_at"] ||= Time.now.to_f
|
72
|
-
worker_to_push = with_job_jid
|
73
|
-
Esse::AsyncIndexing::SERVICES[service].push(worker_to_push)
|
74
|
-
end
|
75
|
-
|
76
|
-
def eql?(other)
|
77
|
-
return false unless other.is_a?(self.class)
|
78
|
-
|
79
|
-
worker_class == other.worker_class &&
|
80
|
-
payload == other.payload &&
|
81
|
-
options == other.options
|
82
|
-
end
|
83
|
-
alias_method :==, :eql?
|
84
|
-
end
|
85
|
-
end
|
@@ -1,28 +0,0 @@
|
|
1
|
-
# frizen_string_literal: true
|
2
|
-
|
3
|
-
require_relative "shared_class_methods"
|
4
|
-
|
5
|
-
module Esse::AsyncIndexing
|
6
|
-
module Workers
|
7
|
-
module Faktory
|
8
|
-
def self.extended(base)
|
9
|
-
base.include(::Faktory::Job) if defined?(::Faktory)
|
10
|
-
base.extend SharedClassMethods
|
11
|
-
base.extend ClassMethods
|
12
|
-
end
|
13
|
-
|
14
|
-
module ClassMethods
|
15
|
-
def service_worker_options
|
16
|
-
default_queue = Esse.config.async_indexing.faktory.workers.dig(name, :queue)
|
17
|
-
default_retry = Esse.config.async_indexing.faktory.workers.dig(name, :retry)
|
18
|
-
default_queue ||= ::Faktory.default_job_options["queue"] if defined?(::Faktory)
|
19
|
-
default_retry ||= ::Faktory.default_job_options["retry"] if defined?(::Faktory)
|
20
|
-
{
|
21
|
-
queue: default_queue || "default",
|
22
|
-
retry: default_retry || 25
|
23
|
-
}
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
@@ -1,26 +0,0 @@
|
|
1
|
-
# frizen_string_literal: true
|
2
|
-
|
3
|
-
module Esse::AsyncIndexing
|
4
|
-
module Workers
|
5
|
-
module SharedClassMethods
|
6
|
-
def perform_async(*args)
|
7
|
-
build_worker.with_args(*args).push
|
8
|
-
end
|
9
|
-
|
10
|
-
def perform_in(interval, *args)
|
11
|
-
build_worker.with_args(*args).at(interval).push
|
12
|
-
end
|
13
|
-
alias_method :perform_at, :perform_in
|
14
|
-
|
15
|
-
protected
|
16
|
-
|
17
|
-
def service_worker_options
|
18
|
-
{}
|
19
|
-
end
|
20
|
-
|
21
|
-
def build_worker
|
22
|
-
Esse::AsyncIndexing.worker(name, **service_worker_options.merge(bg_worker_options))
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|