chewy 7.5.0 → 7.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ruby.yml +12 -0
- data/.rubocop.yml +3 -0
- data/CHANGELOG.md +22 -1
- data/README.md +24 -3
- data/chewy.gemspec +1 -1
- data/gemfiles/base.gemfile +3 -3
- data/lib/chewy/config.rb +7 -3
- data/lib/chewy/errors.rb +5 -2
- data/lib/chewy/index/adapter/active_record.rb +12 -2
- data/lib/chewy/rake_helper.rb +1 -5
- data/lib/chewy/strategy/delayed_sidekiq/scheduler.rb +33 -16
- data/lib/chewy/strategy/delayed_sidekiq/worker.rb +30 -6
- data/lib/chewy/strategy/delayed_sidekiq.rb +4 -4
- data/lib/chewy/version.rb +1 -1
- data/spec/chewy/config_spec.rb +2 -2
- data/spec/chewy/index/adapter/active_record_spec.rb +62 -0
- data/spec/chewy/strategy/delayed_sidekiq_spec.rb +13 -7
- metadata +6 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a15165f889275fecc6a0d590c3339ce0ac9b7944f916306fd6883e7c2be67747
|
4
|
+
data.tar.gz: 8efc6201add68bf1c378f598934b6c52c74bd9a62056e7aafdd357358d5cd2b0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cfc7f1297fc72fcbdfdbedbcd82c6afe12dd9e15583b4e3467a8a77da89cd1aa8f20b9d0c0a8dd1841275e2916715030e28e9ed10cf510d6985904be9574890e
|
7
|
+
data.tar.gz: 6917027945ce94dab50d2f6d679570be58e4bb86472f1d591805d915ca425ecbd24e4cc13e30a459fe2dae4d572002735b69cef138a5c6038c52803a251b8a54
|
data/.github/workflows/ruby.yml
CHANGED
@@ -23,6 +23,18 @@ jobs:
|
|
23
23
|
env:
|
24
24
|
BUNDLE_GEMFILE: gemfiles/${{ matrix.gemfile }}.gemfile
|
25
25
|
|
26
|
+
services:
|
27
|
+
redis:
|
28
|
+
# Docker Hub image
|
29
|
+
image: redis
|
30
|
+
ports:
|
31
|
+
- '6379:6379'
|
32
|
+
# Set health checks to wait until redis has started
|
33
|
+
options: >-
|
34
|
+
--health-cmd "redis-cli ping"
|
35
|
+
--health-interval 10s
|
36
|
+
--health-timeout 5s
|
37
|
+
--health-retries 5
|
26
38
|
steps:
|
27
39
|
- uses: actions/checkout@v4
|
28
40
|
- uses: ruby/setup-ruby@v1
|
data/.rubocop.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -8,7 +8,28 @@
|
|
8
8
|
|
9
9
|
### Bugs Fixed
|
10
10
|
|
11
|
-
## 7.
|
11
|
+
## 7.6.0 (2024-05-03)
|
12
|
+
|
13
|
+
### Changes
|
14
|
+
|
15
|
+
* [#933](https://github.com/toptal/chewy/pull/933): Relax allowed `elasticsearch` dependency versions. ([@mjankowski][])
|
16
|
+
|
17
|
+
### Bugs Fixed
|
18
|
+
* [#937](https://github.com/toptal/chewy/pull/937): Fix for race condition while using the `delayed_sidekiq` strategy. Also, fix for Redis bloating in case of reindexing error ([@skcc321](https://github.com/skcc321))
|
19
|
+
|
20
|
+
* [#947](https://github.com/toptal/chewy/pull/947): Fix intermittent time-based failure in delayed sidekiq spec. ([@mjankowski][])
|
21
|
+
|
22
|
+
## 7.5.1 (2024-01-30)
|
23
|
+
|
24
|
+
### New Features
|
25
|
+
|
26
|
+
* [#925](https://github.com/toptal/chewy/pull/925): Add configuration option for default scope cleanup behavior. ([@barthez][])
|
27
|
+
|
28
|
+
### Changes
|
29
|
+
|
30
|
+
### Bugs Fixed
|
31
|
+
|
32
|
+
## 7.5.0 (2024-01-15)
|
12
33
|
|
13
34
|
### New Features
|
14
35
|
|
data/README.md
CHANGED
@@ -776,9 +776,12 @@ Chewy.settings[:sidekiq] = {queue: :low}
|
|
776
776
|
|
777
777
|
#### `:delayed_sidekiq`
|
778
778
|
|
779
|
-
It accumulates
|
780
|
-
|
781
|
-
It supports `update_fields` option, so it will
|
779
|
+
It accumulates IDs of records to be reindexed during the latency window in Redis and then performs the reindexing of all accumulated records at once.
|
780
|
+
This strategy is very useful in the case of frequently mutated records.
|
781
|
+
It supports the `update_fields` option, so it will attempt to select just enough data from the database.
|
782
|
+
|
783
|
+
Keep in mind, this strategy does not guarantee reindexing in the event of Sidekiq worker termination or an error during the reindexing phase.
|
784
|
+
This behavior is intentional to prevent continuous growth of Redis db.
|
782
785
|
|
783
786
|
There are three options that can be defined in the index:
|
784
787
|
```ruby
|
@@ -1298,6 +1301,24 @@ While using the `before_es_request_filter`, please consider the following:
|
|
1298
1301
|
* The return value of the proc is disregarded. This filter is intended for inspection or modification of the query rather than generating a response.
|
1299
1302
|
* Any exception raised inside the callback will propagate upward and halt the execution of the query. It is essential to handle potential errors adequately to ensure the stability of your search functionality.
|
1300
1303
|
|
1304
|
+
### Import scope clean-up behavior
|
1305
|
+
|
1306
|
+
Whenever you set the `import_scope` for the index, in the case of ActiveRecord,
|
1307
|
+
options for order, offset and limit will be removed. You can set the behavior of
|
1308
|
+
chewy, before the clean-up itself.
|
1309
|
+
|
1310
|
+
The default behavior is a warning sent to the Chewy logger (`:warn`). Another more
|
1311
|
+
restrictive option is raising an exception (`:raise`). Both options have a
|
1312
|
+
negative impact on performance since verifying whether the code uses any of
|
1313
|
+
these options requires building AREL query.
|
1314
|
+
|
1315
|
+
To avoid the loading time impact, you can ignore the check (`:ignore`) before
|
1316
|
+
the clean-up.
|
1317
|
+
|
1318
|
+
```
|
1319
|
+
Chewy.import_scope_cleanup_behavior = :ignore
|
1320
|
+
```
|
1321
|
+
|
1301
1322
|
## Contributing
|
1302
1323
|
|
1303
1324
|
1. Fork it (http://github.com/toptal/chewy/fork)
|
data/chewy.gemspec
CHANGED
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.require_paths = ['lib']
|
18
18
|
|
19
19
|
spec.add_dependency 'activesupport', '>= 5.2' # Remove with major version bump, 8.x
|
20
|
-
spec.add_dependency 'elasticsearch', '>= 7.
|
20
|
+
spec.add_dependency 'elasticsearch', '>= 7.14.0', '< 8'
|
21
21
|
spec.add_dependency 'elasticsearch-dsl'
|
22
22
|
spec.metadata['rubygems_mfa_required'] = 'true'
|
23
23
|
end
|
data/gemfiles/base.gemfile
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
gem 'database_cleaner'
|
2
2
|
gem 'elasticsearch-extensions'
|
3
3
|
gem 'method_source'
|
4
|
-
gem 'mock_redis'
|
5
4
|
gem 'rake'
|
5
|
+
gem 'redis', require: false
|
6
6
|
gem 'rspec', '>= 3.7.0'
|
7
7
|
gem 'rspec-collection_matchers'
|
8
8
|
gem 'rspec-its'
|
9
|
-
gem 'rubocop', '1.
|
10
|
-
gem 'sqlite3'
|
9
|
+
gem 'rubocop', '1.63.4'
|
10
|
+
gem 'sqlite3', '~> 1.4'
|
11
11
|
gem 'timecop'
|
12
12
|
gem 'unparser'
|
data/lib/chewy/config.rb
CHANGED
@@ -40,7 +40,10 @@ module Chewy
|
|
40
40
|
# Default field type for any field in any Chewy type. Defaults to 'text'.
|
41
41
|
:default_field_type,
|
42
42
|
# Callback called on each search request to be done into ES
|
43
|
-
:before_es_request_filter
|
43
|
+
:before_es_request_filter,
|
44
|
+
# Behavior when import scope for index includes order, offset or limit.
|
45
|
+
# Can be :ignore, :warn, :raise. Defaults to :warn
|
46
|
+
:import_scope_cleanup_behavior
|
44
47
|
|
45
48
|
attr_reader :transport_logger, :transport_tracer,
|
46
49
|
# Chewy search request DSL base class, used by every index.
|
@@ -62,16 +65,17 @@ module Chewy
|
|
62
65
|
@indices_path = 'app/chewy'
|
63
66
|
@default_root_options = {}
|
64
67
|
@default_field_type = 'text'.freeze
|
68
|
+
@import_scope_cleanup_behavior = :warn
|
65
69
|
@search_class = build_search_class(Chewy::Search::Request)
|
66
70
|
end
|
67
71
|
|
68
72
|
def transport_logger=(logger)
|
69
|
-
Chewy.client.transport.logger = logger
|
73
|
+
Chewy.client.transport.transport.logger = logger
|
70
74
|
@transport_logger = logger
|
71
75
|
end
|
72
76
|
|
73
77
|
def transport_tracer=(tracer)
|
74
|
-
Chewy.client.transport.tracer = tracer
|
78
|
+
Chewy.client.transport.transport.tracer = tracer
|
75
79
|
@transport_tracer = tracer
|
76
80
|
end
|
77
81
|
|
data/lib/chewy/errors.rb
CHANGED
@@ -7,7 +7,7 @@ module Chewy
|
|
7
7
|
|
8
8
|
class UndefinedUpdateStrategy < Error
|
9
9
|
def initialize(_type)
|
10
|
-
super
|
10
|
+
super(<<-MESSAGE)
|
11
11
|
Index update strategy is undefined for current context.
|
12
12
|
Please wrap your code with `Chewy.strategy(:strategy_name) block.`
|
13
13
|
MESSAGE
|
@@ -27,7 +27,7 @@ module Chewy
|
|
27
27
|
message << " on #{documents.count} documents: #{documents}\n"
|
28
28
|
end
|
29
29
|
end
|
30
|
-
super
|
30
|
+
super(message)
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
@@ -36,4 +36,7 @@ module Chewy
|
|
36
36
|
super("`#{join_field_type}` set for the join field `#{join_field_name}` is not on the :relations list (#{relations})")
|
37
37
|
end
|
38
38
|
end
|
39
|
+
|
40
|
+
class ImportScopeCleanupError < Error
|
41
|
+
end
|
39
42
|
end
|
@@ -13,9 +13,19 @@ module Chewy
|
|
13
13
|
private
|
14
14
|
|
15
15
|
def cleanup_default_scope!
|
16
|
-
|
16
|
+
behavior = Chewy.config.import_scope_cleanup_behavior
|
17
|
+
|
18
|
+
if behavior != :ignore && (@default_scope.arel.orders.present? ||
|
17
19
|
@default_scope.arel.limit.present? || @default_scope.arel.offset.present?)
|
18
|
-
|
20
|
+
if behavior == :warn && Chewy.logger
|
21
|
+
gem_dir = File.realpath('../..', __dir__)
|
22
|
+
source = caller.grep_v(Regexp.new(gem_dir)).first
|
23
|
+
Chewy.logger.warn(
|
24
|
+
"Default type scope order, limit and offset are ignored and will be nullified (called from: #{source})"
|
25
|
+
)
|
26
|
+
elsif behavior == :raise
|
27
|
+
raise ImportScopeCleanupError, 'Default type scope order, limit and offset are ignored and will be nullified'
|
28
|
+
end
|
19
29
|
end
|
20
30
|
|
21
31
|
@default_scope = @default_scope.reorder(nil).limit(nil).offset(nil)
|
data/lib/chewy/rake_helper.rb
CHANGED
@@ -320,11 +320,7 @@ module Chewy
|
|
320
320
|
all_indexes
|
321
321
|
end
|
322
322
|
|
323
|
-
indexes
|
324
|
-
indexes - normalize_indexes(Array.wrap(except))
|
325
|
-
else
|
326
|
-
indexes
|
327
|
-
end
|
323
|
+
indexes -= normalize_indexes(Array.wrap(except)) if except.present?
|
328
324
|
|
329
325
|
indexes.sort_by(&:derivable_name)
|
330
326
|
end
|
@@ -12,13 +12,43 @@ module Chewy
|
|
12
12
|
class DelayedSidekiq
|
13
13
|
require_relative 'worker'
|
14
14
|
|
15
|
+
LUA_SCRIPT = <<~LUA
|
16
|
+
local timechunk_key = KEYS[1]
|
17
|
+
local timechunks_key = KEYS[2]
|
18
|
+
local serialize_data = ARGV[1]
|
19
|
+
local at = ARGV[2]
|
20
|
+
local ttl = tonumber(ARGV[3])
|
21
|
+
|
22
|
+
local schedule_job = false
|
23
|
+
|
24
|
+
-- Check if the 'sadd?' method is available
|
25
|
+
if redis.call('exists', 'sadd?') == 1 then
|
26
|
+
redis.call('sadd?', timechunk_key, serialize_data)
|
27
|
+
else
|
28
|
+
redis.call('sadd', timechunk_key, serialize_data)
|
29
|
+
end
|
30
|
+
|
31
|
+
-- Set expiration for timechunk_key
|
32
|
+
redis.call('expire', timechunk_key, ttl)
|
33
|
+
|
34
|
+
-- Check if timechunk_key exists in the sorted set
|
35
|
+
if not redis.call('zrank', timechunks_key, timechunk_key) then
|
36
|
+
-- Add timechunk_key to the sorted set
|
37
|
+
redis.call('zadd', timechunks_key, at, timechunk_key)
|
38
|
+
-- Set expiration for timechunks_key
|
39
|
+
redis.call('expire', timechunks_key, ttl)
|
40
|
+
schedule_job = true
|
41
|
+
end
|
42
|
+
|
43
|
+
return schedule_job
|
44
|
+
LUA
|
45
|
+
|
15
46
|
class Scheduler
|
16
47
|
DEFAULT_TTL = 60 * 60 * 24 # in seconds
|
17
48
|
DEFAULT_LATENCY = 10
|
18
49
|
DEFAULT_MARGIN = 2
|
19
50
|
DEFAULT_QUEUE = 'chewy'
|
20
51
|
KEY_PREFIX = 'chewy:delayed_sidekiq'
|
21
|
-
ALL_SETS_KEY = "#{KEY_PREFIX}:all_sets".freeze
|
22
52
|
FALLBACK_FIELDS = 'all'
|
23
53
|
FIELDS_IDS_SEPARATOR = ';'
|
24
54
|
IDS_SEPARATOR = ','
|
@@ -67,21 +97,8 @@ module Chewy
|
|
67
97
|
# | chewy:delayed_sidekiq:CitiesIndex:1679347868
|
68
98
|
def postpone
|
69
99
|
::Sidekiq.redis do |redis|
|
70
|
-
#
|
71
|
-
if redis.
|
72
|
-
redis.sadd?(ALL_SETS_KEY, timechunks_key)
|
73
|
-
redis.sadd?(timechunk_key, serialize_data)
|
74
|
-
else
|
75
|
-
redis.sadd(ALL_SETS_KEY, timechunks_key)
|
76
|
-
redis.sadd(timechunk_key, serialize_data)
|
77
|
-
end
|
78
|
-
|
79
|
-
redis.expire(timechunk_key, ttl)
|
80
|
-
|
81
|
-
unless redis.zrank(timechunks_key, timechunk_key)
|
82
|
-
redis.zadd(timechunks_key, at, timechunk_key)
|
83
|
-
redis.expire(timechunks_key, ttl)
|
84
|
-
|
100
|
+
# do the redis stuff in a single command to avoid concurrency issues
|
101
|
+
if redis.eval(LUA_SCRIPT, keys: [timechunk_key, timechunks_key], argv: [serialize_data, at, ttl])
|
85
102
|
::Sidekiq::Client.push(
|
86
103
|
'queue' => sidekiq_queue,
|
87
104
|
'at' => at + margin,
|
@@ -6,13 +6,40 @@ module Chewy
|
|
6
6
|
class Worker
|
7
7
|
include ::Sidekiq::Worker
|
8
8
|
|
9
|
+
LUA_SCRIPT = <<~LUA
|
10
|
+
local type = ARGV[1]
|
11
|
+
local score = tonumber(ARGV[2])
|
12
|
+
local prefix = ARGV[3]
|
13
|
+
local timechunks_key = prefix .. ":" .. type .. ":timechunks"
|
14
|
+
|
15
|
+
-- Get timechunk_keys with scores less than or equal to the specified score
|
16
|
+
local timechunk_keys = redis.call('zrangebyscore', timechunks_key, '-inf', score)
|
17
|
+
|
18
|
+
-- Get all members from the sets associated with the timechunk_keys
|
19
|
+
local members = {}
|
20
|
+
for _, timechunk_key in ipairs(timechunk_keys) do
|
21
|
+
local set_members = redis.call('smembers', timechunk_key)
|
22
|
+
for _, member in ipairs(set_members) do
|
23
|
+
table.insert(members, member)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
-- Remove timechunk_keys and their associated sets
|
28
|
+
for _, timechunk_key in ipairs(timechunk_keys) do
|
29
|
+
redis.call('del', timechunk_key)
|
30
|
+
end
|
31
|
+
|
32
|
+
-- Remove timechunks with scores less than or equal to the specified score
|
33
|
+
redis.call('zremrangebyscore', timechunks_key, '-inf', score)
|
34
|
+
|
35
|
+
return members
|
36
|
+
LUA
|
37
|
+
|
9
38
|
def perform(type, score, options = {})
|
10
39
|
options[:refresh] = !Chewy.disable_refresh_async if Chewy.disable_refresh_async
|
11
40
|
|
12
41
|
::Sidekiq.redis do |redis|
|
13
|
-
|
14
|
-
timechunk_keys = redis.zrangebyscore(timechunks_key, -1, score)
|
15
|
-
members = timechunk_keys.flat_map { |timechunk_key| redis.smembers(timechunk_key) }.compact
|
42
|
+
members = redis.eval(LUA_SCRIPT, keys: [], argv: [type, score, Scheduler::KEY_PREFIX])
|
16
43
|
|
17
44
|
# extract ids and fields & do the reset of records
|
18
45
|
ids, fields = extract_ids_and_fields(members)
|
@@ -22,9 +49,6 @@ module Chewy
|
|
22
49
|
index.strategy_config.delayed_sidekiq.reindex_wrapper.call do
|
23
50
|
options.any? ? index.import!(ids, **options) : index.import!(ids)
|
24
51
|
end
|
25
|
-
|
26
|
-
redis.del(timechunk_keys)
|
27
|
-
redis.zremrangebyscore(timechunks_key, -1, score)
|
28
52
|
end
|
29
53
|
end
|
30
54
|
|
@@ -9,11 +9,11 @@ module Chewy
|
|
9
9
|
# leak and potential flaky tests.
|
10
10
|
def self.clear_timechunks!
|
11
11
|
::Sidekiq.redis do |redis|
|
12
|
-
|
13
|
-
break if timechunk_sets.empty?
|
12
|
+
keys_to_delete = redis.keys("#{Scheduler::KEY_PREFIX}*")
|
14
13
|
|
15
|
-
|
16
|
-
|
14
|
+
# Delete keys one by one
|
15
|
+
keys_to_delete.each do |key|
|
16
|
+
redis.del(key)
|
17
17
|
end
|
18
18
|
end
|
19
19
|
end
|
data/lib/chewy/version.rb
CHANGED
data/spec/chewy/config_spec.rb
CHANGED
@@ -22,7 +22,7 @@ describe Chewy::Config do
|
|
22
22
|
|
23
23
|
specify do
|
24
24
|
expect { subject.transport_logger = logger }
|
25
|
-
.to change { Chewy.client.transport.logger }.to(logger)
|
25
|
+
.to change { Chewy.client.transport.transport.logger }.to(logger)
|
26
26
|
end
|
27
27
|
specify do
|
28
28
|
expect { subject.transport_logger = logger }
|
@@ -40,7 +40,7 @@ describe Chewy::Config do
|
|
40
40
|
|
41
41
|
specify do
|
42
42
|
expect { subject.transport_tracer = tracer }
|
43
|
-
.to change { Chewy.client.transport.tracer }.to(tracer)
|
43
|
+
.to change { Chewy.client.transport.transport.tracer }.to(tracer)
|
44
44
|
end
|
45
45
|
specify do
|
46
46
|
expect { subject.transport_tracer = tracer }
|
@@ -35,6 +35,68 @@ describe Chewy::Index::Adapter::ActiveRecord, :active_record do
|
|
35
35
|
specify { expect(described_class.new(City.where(rating: 10)).default_scope).to eq(City.where(rating: 10)) }
|
36
36
|
end
|
37
37
|
|
38
|
+
describe '.new' do
|
39
|
+
context 'with logger' do
|
40
|
+
let(:test_logger) { Logger.new('/dev/null') }
|
41
|
+
let(:default_scope_behavior) { :warn }
|
42
|
+
|
43
|
+
around do |example|
|
44
|
+
previous_logger = Chewy.logger
|
45
|
+
Chewy.logger = test_logger
|
46
|
+
|
47
|
+
previous_default_scope_behavior = Chewy.config.import_scope_cleanup_behavior
|
48
|
+
Chewy.config.import_scope_cleanup_behavior = default_scope_behavior
|
49
|
+
|
50
|
+
example.run
|
51
|
+
ensure
|
52
|
+
Chewy.logger = previous_logger
|
53
|
+
Chewy.config.import_scope_cleanup_behavior = previous_default_scope_behavior
|
54
|
+
end
|
55
|
+
|
56
|
+
specify do
|
57
|
+
expect(test_logger).to receive(:warn)
|
58
|
+
described_class.new(City.order(:id))
|
59
|
+
end
|
60
|
+
|
61
|
+
specify do
|
62
|
+
expect(test_logger).to receive(:warn)
|
63
|
+
described_class.new(City.offset(10))
|
64
|
+
end
|
65
|
+
|
66
|
+
specify do
|
67
|
+
expect(test_logger).to receive(:warn)
|
68
|
+
described_class.new(City.limit(10))
|
69
|
+
end
|
70
|
+
|
71
|
+
context 'ignore import scope warning' do
|
72
|
+
let(:default_scope_behavior) { :ignore }
|
73
|
+
|
74
|
+
specify do
|
75
|
+
expect(test_logger).not_to receive(:warn)
|
76
|
+
described_class.new(City.order(:id))
|
77
|
+
end
|
78
|
+
|
79
|
+
specify do
|
80
|
+
expect(test_logger).not_to receive(:warn)
|
81
|
+
described_class.new(City.offset(10))
|
82
|
+
end
|
83
|
+
|
84
|
+
specify do
|
85
|
+
expect(test_logger).not_to receive(:warn)
|
86
|
+
described_class.new(City.limit(10))
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'raise exception on import scope with order/limit/offset' do
|
91
|
+
let(:default_scope_behavior) { :raise }
|
92
|
+
|
93
|
+
specify { expect { described_class.new(City.order(:id)) }.to raise_error(Chewy::ImportScopeCleanupError) }
|
94
|
+
specify { expect { described_class.new(City.limit(10)) }.to raise_error(Chewy::ImportScopeCleanupError) }
|
95
|
+
specify { expect { described_class.new(City.offset(10)) }.to raise_error(Chewy::ImportScopeCleanupError) }
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
38
100
|
describe '#type_name' do
|
39
101
|
specify { expect(described_class.new(City).type_name).to eq('city') }
|
40
102
|
specify { expect(described_class.new(City.order(:id)).type_name).to eq('city') }
|
@@ -2,7 +2,7 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
if defined?(Sidekiq)
|
4
4
|
require 'sidekiq/testing'
|
5
|
-
require '
|
5
|
+
require 'redis'
|
6
6
|
|
7
7
|
describe Chewy::Strategy::DelayedSidekiq do
|
8
8
|
around do |example|
|
@@ -10,9 +10,10 @@ if defined?(Sidekiq)
|
|
10
10
|
end
|
11
11
|
|
12
12
|
before do
|
13
|
-
redis =
|
13
|
+
redis = Redis.new
|
14
14
|
allow(Sidekiq).to receive(:redis).and_yield(redis)
|
15
15
|
Sidekiq::Worker.clear_all
|
16
|
+
described_class.clear_timechunks!
|
16
17
|
end
|
17
18
|
|
18
19
|
before do
|
@@ -35,7 +36,7 @@ if defined?(Sidekiq)
|
|
35
36
|
|
36
37
|
it "respects 'refresh: false' options" do
|
37
38
|
allow(Chewy).to receive(:disable_refresh_async).and_return(true)
|
38
|
-
expect(CitiesIndex).to receive(:import!).with([city.id, other_city.id], refresh: false)
|
39
|
+
expect(CitiesIndex).to receive(:import!).with(match_array([city.id, other_city.id]), refresh: false)
|
39
40
|
scheduler = Chewy::Strategy::DelayedSidekiq::Scheduler.new(CitiesIndex, [city.id, other_city.id])
|
40
41
|
scheduler.postpone
|
41
42
|
Chewy::Strategy::DelayedSidekiq::Worker.drain
|
@@ -47,7 +48,7 @@ if defined?(Sidekiq)
|
|
47
48
|
expect(Sidekiq::Client).to receive(:push).with(
|
48
49
|
hash_including(
|
49
50
|
'queue' => 'chewy',
|
50
|
-
'at' =>
|
51
|
+
'at' => expected_at_time.to_i,
|
51
52
|
'class' => Chewy::Strategy::DelayedSidekiq::Worker,
|
52
53
|
'args' => ['CitiesIndex', an_instance_of(Integer)]
|
53
54
|
)
|
@@ -62,6 +63,11 @@ if defined?(Sidekiq)
|
|
62
63
|
end
|
63
64
|
end
|
64
65
|
end
|
66
|
+
|
67
|
+
def expected_at_time
|
68
|
+
target = described_class::Scheduler::DEFAULT_LATENCY.seconds.from_now.to_i
|
69
|
+
target - (target % described_class::Scheduler::DEFAULT_LATENCY) + described_class::Scheduler::DEFAULT_MARGIN.seconds
|
70
|
+
end
|
65
71
|
end
|
66
72
|
|
67
73
|
context 'with custom config' do
|
@@ -103,7 +109,7 @@ if defined?(Sidekiq)
|
|
103
109
|
context 'two reindex call within the timewindow' do
|
104
110
|
it 'accumulates all ids does the reindex one time' do
|
105
111
|
Timecop.freeze do
|
106
|
-
expect(CitiesIndex).to receive(:import!).with([
|
112
|
+
expect(CitiesIndex).to receive(:import!).with(match_array([city.id, other_city.id])).once
|
107
113
|
scheduler = Chewy::Strategy::DelayedSidekiq::Scheduler.new(CitiesIndex, [city.id])
|
108
114
|
scheduler.postpone
|
109
115
|
scheduler = Chewy::Strategy::DelayedSidekiq::Scheduler.new(CitiesIndex, [other_city.id])
|
@@ -115,7 +121,7 @@ if defined?(Sidekiq)
|
|
115
121
|
context 'one call with update_fields another one without update_fields' do
|
116
122
|
it 'does reindex of all fields' do
|
117
123
|
Timecop.freeze do
|
118
|
-
expect(CitiesIndex).to receive(:import!).with([
|
124
|
+
expect(CitiesIndex).to receive(:import!).with(match_array([city.id, other_city.id])).once
|
119
125
|
scheduler = Chewy::Strategy::DelayedSidekiq::Scheduler.new(CitiesIndex, [city.id], update_fields: ['name'])
|
120
126
|
scheduler.postpone
|
121
127
|
scheduler = Chewy::Strategy::DelayedSidekiq::Scheduler.new(CitiesIndex, [other_city.id])
|
@@ -128,7 +134,7 @@ if defined?(Sidekiq)
|
|
128
134
|
context 'both calls with different update fields' do
|
129
135
|
it 'deos reindex with union of fields' do
|
130
136
|
Timecop.freeze do
|
131
|
-
expect(CitiesIndex).to receive(:import!).with([
|
137
|
+
expect(CitiesIndex).to receive(:import!).with(match_array([city.id, other_city.id]), update_fields: %w[name description]).once
|
132
138
|
scheduler = Chewy::Strategy::DelayedSidekiq::Scheduler.new(CitiesIndex, [city.id], update_fields: ['name'])
|
133
139
|
scheduler.postpone
|
134
140
|
scheduler = Chewy::Strategy::DelayedSidekiq::Scheduler.new(CitiesIndex, [other_city.id], update_fields: ['description'])
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: chewy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 7.
|
4
|
+
version: 7.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Toptal, LLC
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2024-
|
12
|
+
date: 2024-05-06 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
@@ -31,20 +31,20 @@ dependencies:
|
|
31
31
|
requirements:
|
32
32
|
- - ">="
|
33
33
|
- !ruby/object:Gem::Version
|
34
|
-
version: 7.
|
34
|
+
version: 7.14.0
|
35
35
|
- - "<"
|
36
36
|
- !ruby/object:Gem::Version
|
37
|
-
version:
|
37
|
+
version: '8'
|
38
38
|
type: :runtime
|
39
39
|
prerelease: false
|
40
40
|
version_requirements: !ruby/object:Gem::Requirement
|
41
41
|
requirements:
|
42
42
|
- - ">="
|
43
43
|
- !ruby/object:Gem::Version
|
44
|
-
version: 7.
|
44
|
+
version: 7.14.0
|
45
45
|
- - "<"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: '8'
|
48
48
|
- !ruby/object:Gem::Dependency
|
49
49
|
name: elasticsearch-dsl
|
50
50
|
requirement: !ruby/object:Gem::Requirement
|