chewy 7.5.1 → 8.0.0.pre.beta

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.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.github/CODEOWNERS +1 -1
  3. data/.github/workflows/ruby.yml +17 -5
  4. data/CHANGELOG.md +23 -0
  5. data/README.md +39 -4
  6. data/chewy.gemspec +3 -2
  7. data/docker-compose.yml +15 -0
  8. data/gemfiles/base.gemfile +3 -3
  9. data/lib/chewy/errors.rb +3 -0
  10. data/lib/chewy/fields/root.rb +1 -1
  11. data/lib/chewy/index/actions.rb +5 -5
  12. data/lib/chewy/index/aliases.rb +1 -1
  13. data/lib/chewy/index/syncer.rb +1 -1
  14. data/lib/chewy/minitest/helpers.rb +1 -1
  15. data/lib/chewy/search/request.rb +4 -4
  16. data/lib/chewy/search/response.rb +7 -0
  17. data/lib/chewy/search/scrolling.rb +2 -1
  18. data/lib/chewy/strategy/delayed_sidekiq/scheduler.rb +33 -16
  19. data/lib/chewy/strategy/delayed_sidekiq/worker.rb +30 -6
  20. data/lib/chewy/strategy/delayed_sidekiq.rb +4 -4
  21. data/lib/chewy/version.rb +1 -1
  22. data/lib/chewy.rb +4 -0
  23. data/spec/chewy/elastic_client_spec.rb +1 -1
  24. data/spec/chewy/fields/base_spec.rb +2 -2
  25. data/spec/chewy/fields/time_fields_spec.rb +1 -1
  26. data/spec/chewy/index/actions_spec.rb +9 -9
  27. data/spec/chewy/index/aliases_spec.rb +1 -1
  28. data/spec/chewy/index/import/bulk_builder_spec.rb +2 -2
  29. data/spec/chewy/index/import/bulk_request_spec.rb +1 -1
  30. data/spec/chewy/index/import/routine_spec.rb +1 -1
  31. data/spec/chewy/index/import_spec.rb +15 -15
  32. data/spec/chewy/index/observe/callback_spec.rb +1 -1
  33. data/spec/chewy/index/specification_spec.rb +1 -4
  34. data/spec/chewy/index/syncer_spec.rb +1 -1
  35. data/spec/chewy/index_spec.rb +1 -1
  36. data/spec/chewy/journal_spec.rb +2 -2
  37. data/spec/chewy/minitest/helpers_spec.rb +1 -1
  38. data/spec/chewy/multi_search_spec.rb +1 -1
  39. data/spec/chewy/rake_helper_spec.rb +1 -1
  40. data/spec/chewy/rspec/update_index_spec.rb +1 -1
  41. data/spec/chewy/runtime_spec.rb +2 -2
  42. data/spec/chewy/search/loader_spec.rb +1 -1
  43. data/spec/chewy/search/pagination/kaminari_examples.rb +1 -1
  44. data/spec/chewy/search/request_spec.rb +1 -1
  45. data/spec/chewy/search/response_spec.rb +2 -2
  46. data/spec/chewy/search/scrolling_spec.rb +1 -1
  47. data/spec/chewy/search_spec.rb +1 -1
  48. data/spec/chewy/stash_spec.rb +1 -1
  49. data/spec/chewy/strategy/delayed_sidekiq_spec.rb +13 -7
  50. data/spec/chewy/strategy_spec.rb +1 -1
  51. data/spec/chewy_spec.rb +6 -5
  52. data/spec/spec_helper.rb +26 -0
  53. metadata +14 -13
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 64f061f379d740c56b7af2678ec03e3c80c1bd4c072b2aa3f68bf7803d4bc0fe
4
- data.tar.gz: 6226557f9cec700d91473f36bb8623ff5bbf838211463188ac0f83eaf0ab227d
3
+ metadata.gz: fe6459bb964c9d44912601a2a5abc6ea93ea7ac7be94c384673ade2ce68fb9e6
4
+ data.tar.gz: 397d2104f889f9e9232ed673b3fe5dc50fe4c13f1330b4ce9b1b1e45f9a11e16
5
5
  SHA512:
6
- metadata.gz: 8cb278cc5fa838a97e0c9fb94c90ea08d4a84effb041a809f850a267514c61ce78f1a919a8a0fdc5119ca968e217fe9b0aa38c307f9589f8413501f690efb314
7
- data.tar.gz: 50ad4271e4948b22b626202843be7107fcc720fd3da490c14a372ca018ab0e35c0e151d5dc5b55f23b7c382a0d19cf72f7cc63e40a2dc1fc0ca286c1de717941
6
+ metadata.gz: ebe662c3e11aaebd6fb8de8058ed9199d94b7eb80e7f4b6347c0fe98481c37cdb6be51e72d13645e627ae7d653d43c4bcd6a9a1f81b4eafdbb7371c814f2e847
7
+ data.tar.gz: 0e3b1d9b5eb0724fb1b2453d75e7980d9d7c1a3b341dca3934c366c7ba6ec5242bd9e647538486c9be6203d1ca9a5c6f18bcefcfc7ea64cdf8a31b7893af9f72
data/.github/CODEOWNERS CHANGED
@@ -1 +1 @@
1
- .github/workflows @toptal/platform-sre
1
+ .github/workflows @toptal/sre
@@ -23,17 +23,29 @@ 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
29
41
  with:
30
42
  ruby-version: ${{ matrix.ruby }}
31
43
  bundler-cache: true
32
- - name: Run Elasticsearch
33
- uses: elastic/elastic-github-actions/elasticsearch@9de0f78f306e4ebc0838f057e6b754364685e759
34
- with:
35
- stack-version: 7.10.1
36
- port: 9250
44
+ - name: Start containers
45
+ run: |
46
+ docker compose up elasticsearch_test -d
47
+ sleep 15
48
+
37
49
  - name: Tests
38
50
  run: bundle exec rspec
39
51
 
data/CHANGELOG.md CHANGED
@@ -8,6 +8,29 @@
8
8
 
9
9
  ### Bugs Fixed
10
10
 
11
+ ## 8.0.0-beta (2024-08-27)
12
+
13
+ ### New Features
14
+
15
+ * [#962](https://github.com/toptal/chewy/pull/962): ElasticSearch v.8 support added
16
+
17
+ * `delete_all_enabled` setting introduced to align Chewy.massacre with wildcard indices deletion disabled in ES 8 by default
18
+
19
+ ### Changes
20
+
21
+ ### Bugs Fixed
22
+
23
+ ## 7.6.0 (2024-05-03)
24
+
25
+ ### Changes
26
+
27
+ * [#933](https://github.com/toptal/chewy/pull/933): Relax allowed `elasticsearch` dependency versions. ([@mjankowski][])
28
+
29
+ ### Bugs Fixed
30
+ * [#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))
31
+
32
+ * [#947](https://github.com/toptal/chewy/pull/947): Fix intermittent time-based failure in delayed sidekiq spec. ([@mjankowski][])
33
+
11
34
  ## 7.5.1 (2024-01-30)
12
35
 
13
36
  ### New Features
data/README.md CHANGED
@@ -51,6 +51,7 @@ Chewy is compatible with MRI 3.0-3.2¹.
51
51
 
52
52
  | Chewy version | Elasticsearch version |
53
53
  | ------------- | ---------------------------------- |
54
+ | 8.0.0 | 8.x |
54
55
  | 7.2.x | 7.x |
55
56
  | 7.1.x | 7.x |
56
57
  | 7.0.x | 6.8, 7.x |
@@ -97,7 +98,36 @@ development:
97
98
  Make sure you have Elasticsearch up and running. You can [install](https://www.elastic.co/guide/en/elasticsearch/reference/current/install-elasticsearch.html) it locally, but the easiest way is to use [Docker](https://www.docker.com/get-started):
98
99
 
99
100
  ```shell
100
- $ docker run --rm --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" elasticsearch:7.11.1
101
+ $ docker run --rm --name elasticsearch -p 9200:9200 -p 9300:9300 -e "discovery.type=single-node" -e "xpack.security.enabled=false" elasticsearch:8.15.0
102
+ ```
103
+
104
+ ### Security
105
+
106
+ Please note that starting from version 8 ElasticSearch has security features enabled by default.
107
+ Docker command above has it disabled for local testing convenience. If you want to enable it, omit
108
+ `"xpack.security.enabled=false"` part from Docker command, and run these command after starting container (container name `es8` assumed):
109
+
110
+ Reset password for `elastic` user:
111
+ ```
112
+ docker container exec es8 '/usr/share/elasticsearch/bin/elasticsearch-reset-password' -u elastic
113
+ ```
114
+
115
+ Extract CA certificate generated by ElasticSearch on first run:
116
+ ```
117
+ docker container cp es8:/usr/share/elasticsearch/config/certs/http_ca.crt tmp/
118
+ ```
119
+
120
+ And then add them to settings:
121
+
122
+ ```yaml
123
+ # config/chewy.yml
124
+ development:
125
+ host: 'localhost:9200'
126
+ user: 'elastic'
127
+ password: 'SomeLongPassword'
128
+ transport_options:
129
+ ssl:
130
+ ca_file: './tmp/http_ca.crt'
101
131
  ```
102
132
 
103
133
  ### Index
@@ -776,9 +806,12 @@ Chewy.settings[:sidekiq] = {queue: :low}
776
806
 
777
807
  #### `:delayed_sidekiq`
778
808
 
779
- It accumulates ids of records to be reindexed during the latency window in redis and then does the reindexing of all accumulated records at once.
780
- The strategy is very useful in case of frequently mutated records.
781
- It supports `update_fields` option, so it will try to select just enough data from the DB
809
+ 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.
810
+ This strategy is very useful in the case of frequently mutated records.
811
+ It supports the `update_fields` option, so it will attempt to select just enough data from the database.
812
+
813
+ Keep in mind, this strategy does not guarantee reindexing in the event of Sidekiq worker termination or an error during the reindexing phase.
814
+ This behavior is intentional to prevent continuous growth of Redis db.
782
815
 
783
816
  There are three options that can be defined in the index:
784
817
  ```ruby
@@ -938,6 +971,8 @@ Controller actions are wrapped with the configurable value of `Chewy.request_str
938
971
 
939
972
  It is also a good idea to set up the `:bypass` strategy inside your test suite and import objects manually only when needed, and use `Chewy.massacre` when needed to flush test ES indices before every example. This will allow you to minimize unnecessary ES requests and reduce overhead.
940
973
 
974
+ Deprecation note: since version 8 wildcard removing of indices is disabled by default. You can enable it for a cluster with setting `action.destructive_requires_name` to false.
975
+
941
976
  ```ruby
942
977
  RSpec.configure do |config|
943
978
  config.before(:suite) do
data/chewy.gemspec CHANGED
@@ -11,13 +11,14 @@ Gem::Specification.new do |spec|
11
11
  spec.description = 'Chewy provides functionality for Elasticsearch index handling, documents import mappings and chainable query DSL'
12
12
  spec.homepage = 'https://github.com/toptal/chewy'
13
13
  spec.license = 'MIT'
14
+ spec.required_ruby_version = '~> 3.0'
14
15
 
15
16
  spec.files = `git ls-files`.split($RS)
16
17
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
17
18
  spec.require_paths = ['lib']
18
19
 
19
- spec.add_dependency 'activesupport', '>= 5.2' # Remove with major version bump, 8.x
20
- spec.add_dependency 'elasticsearch', '>= 7.12.0', '< 7.14.0'
20
+ spec.add_dependency 'activesupport', '>= 6.1'
21
+ spec.add_dependency 'elasticsearch', '>= 8.14', '< 9.0'
21
22
  spec.add_dependency 'elasticsearch-dsl'
22
23
  spec.metadata['rubygems_mfa_required'] = 'true'
23
24
  end
@@ -0,0 +1,15 @@
1
+ version: "3.4"
2
+ services:
3
+ elasticsearch_test:
4
+ image: "elasticsearch:8.15.0"
5
+ environment:
6
+ - bootstrap.memory_lock=${ES_MEMORY_LOCK:-false}
7
+ - "ES_JAVA_OPTS=-Xms${TEST_ES_HEAP_SIZE:-500m} -Xmx${TEST_ES_HEAP_SIZE:-500m}"
8
+ - discovery.type=single-node
9
+ - xpack.security.enabled=false
10
+ ports:
11
+ - "127.0.0.1:9250:9200"
12
+ ulimits:
13
+ nofile:
14
+ soft: 65536
15
+ hard: 65536
@@ -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.60.1'
10
- gem 'sqlite3'
9
+ gem 'rubocop', '1.65.1'
10
+ gem 'sqlite3', '~> 1.4'
11
11
  gem 'timecop'
12
12
  gem 'unparser'
data/lib/chewy/errors.rb CHANGED
@@ -39,4 +39,7 @@ module Chewy
39
39
 
40
40
  class ImportScopeCleanupError < Error
41
41
  end
42
+
43
+ class FeatureDisabled < Error
44
+ end
42
45
  end
@@ -4,7 +4,7 @@ module Chewy
4
4
  attr_reader :dynamic_templates, :id
5
5
 
6
6
  def initialize(name, **options)
7
- super(name, **options)
7
+ super
8
8
 
9
9
  @value ||= -> { self }
10
10
  @dynamic_templates = []
@@ -32,7 +32,7 @@ module Chewy
32
32
  #
33
33
  def create(*args, **kwargs)
34
34
  create!(*args, **kwargs)
35
- rescue Elasticsearch::Transport::Transport::Errors::BadRequest
35
+ rescue Elastic::Transport::Transport::Errors::BadRequest
36
36
  false
37
37
  end
38
38
 
@@ -83,9 +83,9 @@ module Chewy
83
83
  result = client.indices.delete index: index_names.join(',')
84
84
  Chewy.wait_for_status if result
85
85
  result
86
- # es-ruby >= 1.0.10 handles Elasticsearch::Transport::Transport::Errors::NotFound
86
+ # es-ruby >= 1.0.10 handles Elastic::Transport::Transport::Errors::NotFound
87
87
  # by itself, rescue is for previous versions
88
- rescue Elasticsearch::Transport::Transport::Errors::NotFound
88
+ rescue Elastic::Transport::Transport::Errors::NotFound
89
89
  false
90
90
  end
91
91
 
@@ -99,9 +99,9 @@ module Chewy
99
99
  # UsersIndex.delete '01-2014' # deletes `users_01-2014` index
100
100
  #
101
101
  def delete!(suffix = nil)
102
- # es-ruby >= 1.0.10 handles Elasticsearch::Transport::Transport::Errors::NotFound
102
+ # es-ruby >= 1.0.10 handles Elastic::Transport::Transport::Errors::NotFound
103
103
  # by itself, so it is raised here
104
- delete(suffix) or raise Elasticsearch::Transport::Transport::Errors::NotFound
104
+ delete(suffix) or raise Elastic::Transport::Transport::Errors::NotFound
105
105
  end
106
106
 
107
107
  # Deletes and recreates index. Supports suffixes.
@@ -22,7 +22,7 @@ module Chewy
22
22
 
23
23
  def empty_if_not_found
24
24
  yield
25
- rescue Elasticsearch::Transport::Transport::Errors::NotFound
25
+ rescue Elastic::Transport::Transport::Errors::NotFound
26
26
  []
27
27
  end
28
28
  end
@@ -213,7 +213,7 @@ module Chewy
213
213
  @outdated_sync_field_type = mappings
214
214
  .fetch('properties', {})
215
215
  .fetch(@index.outdated_sync_field.to_s, {})['type']
216
- rescue Elasticsearch::Transport::Transport::Errors::NotFound
216
+ rescue Elastic::Transport::Transport::Errors::NotFound
217
217
  nil
218
218
  end
219
219
  end
@@ -142,7 +142,7 @@ module Chewy
142
142
  teardown do
143
143
  # always destroy indexes between tests
144
144
  # Prevent croll pollution of test cases due to indexing
145
- Chewy.massacre
145
+ drop_indices
146
146
  end
147
147
  end
148
148
  end
@@ -46,7 +46,7 @@ module Chewy
46
46
 
47
47
  delegate :hits, :wrappers, :objects, :records, :documents,
48
48
  :object_hash, :record_hash, :document_hash,
49
- :total, :max_score, :took, :timed_out?, to: :response
49
+ :total, :max_score, :took, :timed_out?, :terminated_early?, to: :response
50
50
  delegate :each, :size, :to_a, :[], to: :wrappers
51
51
  alias_method :to_ary, :to_a
52
52
  alias_method :total_count, :total
@@ -854,7 +854,7 @@ module Chewy
854
854
  else
855
855
  Chewy.client.count(only(WHERE_STORAGES).render)['count']
856
856
  end
857
- rescue Elasticsearch::Transport::Transport::Errors::NotFound
857
+ rescue Elastic::Transport::Transport::Errors::NotFound
858
858
  0
859
859
  end
860
860
 
@@ -891,7 +891,7 @@ module Chewy
891
891
  def first(limit = UNDEFINED)
892
892
  request_limit = limit == UNDEFINED ? 1 : limit
893
893
 
894
- if performed? && (request_limit <= size || size == total)
894
+ if performed? && (terminated_early? || request_limit <= size || size == total)
895
895
  limit == UNDEFINED ? wrappers.first : wrappers.first(limit)
896
896
  else
897
897
  result = except(EXTRA_STORAGES).limit(request_limit).to_a
@@ -1035,7 +1035,7 @@ module Chewy
1035
1035
  request_body = render.merge(additional)
1036
1036
  ActiveSupport::Notifications.instrument 'search_query.chewy', notification_payload(request: request_body) do
1037
1037
  Chewy.client.search(request_body)
1038
- rescue Elasticsearch::Transport::Transport::Errors::NotFound
1038
+ rescue Elastic::Transport::Transport::Errors::NotFound
1039
1039
  {}
1040
1040
  end
1041
1041
  end
@@ -47,6 +47,13 @@ module Chewy
47
47
  @timed_out ||= @body['timed_out']
48
48
  end
49
49
 
50
+ # Has the request been terminated early?
51
+ #
52
+ # @return [true, false]
53
+ def terminated_early?
54
+ @terminated_early ||= @body['terminated_early']
55
+ end
56
+
50
57
  # The `suggest` response part. Returns empty hash if suggests
51
58
  # were not requested.
52
59
  #
@@ -39,7 +39,8 @@ module Chewy
39
39
  hits = hits.first(last_batch_size) if last_batch_size != 0 && fetched >= total
40
40
  yield(hits) if hits.present?
41
41
  scroll_id = result['_scroll_id']
42
- break if fetched >= total
42
+
43
+ break if result['terminated_early'] || fetched >= total
43
44
 
44
45
  result = perform_scroll(scroll: scroll, scroll_id: scroll_id)
45
46
  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
- # warning: Redis#sadd will always return an Integer in Redis 5.0.0. Use Redis#sadd? instead
71
- if redis.respond_to?(:sadd?)
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
- timechunks_key = "#{Scheduler::KEY_PREFIX}:#{type}:timechunks"
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
- timechunk_sets = redis.smembers(Chewy::Strategy::DelayedSidekiq::Scheduler::ALL_SETS_KEY)
13
- break if timechunk_sets.empty?
12
+ keys_to_delete = redis.keys("#{Scheduler::KEY_PREFIX}*")
14
13
 
15
- redis.pipelined do |pipeline|
16
- timechunk_sets.each { |set| pipeline.del(set) }
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
@@ -1,3 +1,3 @@
1
1
  module Chewy
2
- VERSION = '7.5.1'.freeze
2
+ VERSION = '8.0.0-beta'.freeze
3
3
  end
data/lib/chewy.rb CHANGED
@@ -116,6 +116,10 @@ module Chewy
116
116
  # Be careful, if current prefix is blank, this will destroy all the indexes.
117
117
  #
118
118
  def massacre
119
+ unless Chewy.settings[:delete_all_enabled]
120
+ raise FeatureDisabled, 'Feature disabled by default in ES 8. You can enable it in the cluster and set `delete_all_enabled` option in settings'
121
+ end
122
+
119
123
  Chewy.client.indices.delete(index: [Chewy.configuration[:prefix], '*'].reject(&:blank?).join('_'))
120
124
  Chewy.wait_for_status
121
125
  end
@@ -6,7 +6,7 @@ describe Chewy::ElasticClient do
6
6
  let!(:filter_previous_value) { Chewy.before_es_request_filter }
7
7
 
8
8
  before do
9
- Chewy.massacre
9
+ drop_indices
10
10
  stub_index(:products) do
11
11
  field :id, type: :integer
12
12
  end
@@ -5,7 +5,7 @@ describe Chewy::Fields::Base do
5
5
  specify { expect(described_class.new('name', type: 'integer').options[:type]).to eq('integer') }
6
6
 
7
7
  describe '#compose' do
8
- let(:field) { described_class.new(:name, value: ->(o) { o.value }) }
8
+ let(:field) { described_class.new(:name, value: lambda(&:value)) }
9
9
 
10
10
  specify { expect(field.compose(double(value: 'hello'))).to eq(name: 'hello') }
11
11
  specify { expect(field.compose(double(value: %w[hello world]))).to eq(name: %w[hello world]) }
@@ -23,7 +23,7 @@ describe Chewy::Fields::Base do
23
23
 
24
24
  context 'nested fields' do
25
25
  before do
26
- field.children.push(described_class.new(:subname1, value: ->(o) { o.subvalue1 }))
26
+ field.children.push(described_class.new(:subname1, value: lambda(&:subvalue1)))
27
27
  field.children.push(described_class.new(:subname2, value: -> { subvalue2 }))
28
28
  field.children.push(described_class.new(:subname3))
29
29
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe 'Time fields' do
4
- before { Chewy.massacre }
4
+ before { drop_indices }
5
5
 
6
6
  before do
7
7
  stub_index(:posts) do
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Chewy::Index::Actions do
4
- before { Chewy.massacre }
4
+ before { drop_indices }
5
5
 
6
6
  before do
7
7
  stub_index :dummies
@@ -78,12 +78,12 @@ describe Chewy::Index::Actions do
78
78
  specify do
79
79
  expect do
80
80
  DummiesIndex.create!
81
- end.to raise_error(Elasticsearch::Transport::Transport::Errors::BadRequest).with_message(/already exists.*dummies/)
81
+ end.to raise_error(Elastic::Transport::Transport::Errors::BadRequest).with_message(/already exists.*dummies/)
82
82
  end
83
83
  specify do
84
84
  expect do
85
85
  DummiesIndex.create!('2013')
86
- end.to raise_error(Elasticsearch::Transport::Transport::Errors::BadRequest).with_message(/Invalid alias name \[dummies\]/)
86
+ end.to raise_error(Elastic::Transport::Transport::Errors::BadRequest).with_message(/Invalid alias name \[dummies\]/)
87
87
  end
88
88
  end
89
89
 
@@ -100,7 +100,7 @@ describe Chewy::Index::Actions do
100
100
  specify do
101
101
  expect do
102
102
  DummiesIndex.create!('2013')
103
- end.to raise_error(Elasticsearch::Transport::Transport::Errors::BadRequest).with_message(/already exists.*dummies_2013/)
103
+ end.to raise_error(Elastic::Transport::Transport::Errors::BadRequest).with_message(/already exists.*dummies_2013/)
104
104
  end
105
105
  specify { expect(DummiesIndex.create!('2014')['acknowledged']).to eq(true) }
106
106
 
@@ -190,11 +190,11 @@ describe Chewy::Index::Actions do
190
190
  end
191
191
 
192
192
  describe '.delete!' do
193
- specify { expect { DummiesIndex.delete! }.to raise_error(Elasticsearch::Transport::Transport::Errors::NotFound) }
193
+ specify { expect { DummiesIndex.delete! }.to raise_error(Elastic::Transport::Transport::Errors::NotFound) }
194
194
  specify do
195
195
  expect do
196
196
  DummiesIndex.delete!('2013')
197
- end.to raise_error(Elasticsearch::Transport::Transport::Errors::NotFound)
197
+ end.to raise_error(Elastic::Transport::Transport::Errors::NotFound)
198
198
  end
199
199
 
200
200
  context do
@@ -768,7 +768,7 @@ describe Chewy::Index::Actions do
768
768
  .to receive(:clear_cache)
769
769
  .and_call_original
770
770
  expect { CitiesIndex.clear_cache({index: unexisted_index_name}) }
771
- .to raise_error Elasticsearch::Transport::Transport::Errors::NotFound
771
+ .to raise_error Elastic::Transport::Transport::Errors::NotFound
772
772
  end
773
773
  end
774
774
 
@@ -820,7 +820,7 @@ describe Chewy::Index::Actions do
820
820
  .to receive(:reindex)
821
821
  .and_call_original
822
822
  expect { CitiesIndex.reindex(source: unexisting_index, dest: dest_index_with_prefix) }
823
- .to raise_error Elasticsearch::Transport::Transport::Errors::NotFound
823
+ .to raise_error Elastic::Transport::Transport::Errors::NotFound
824
824
  end
825
825
  end
826
826
 
@@ -883,7 +883,7 @@ describe Chewy::Index::Actions do
883
883
  context 'index name' do
884
884
  specify do
885
885
  expect { CitiesIndex.update_mapping(unexisting_index, body_hash) }
886
- .to raise_error Elasticsearch::Transport::Transport::Errors::NotFound
886
+ .to raise_error Elastic::Transport::Transport::Errors::NotFound
887
887
  end
888
888
  end
889
889
 
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Chewy::Index::Aliases do
4
- before { Chewy.massacre }
4
+ before { drop_indices }
5
5
 
6
6
  before { stub_index :dummies }
7
7
 
@@ -17,7 +17,7 @@ SimpleComment = Class.new do
17
17
  end
18
18
 
19
19
  describe Chewy::Index::Import::BulkBuilder do
20
- before { Chewy.massacre }
20
+ before { drop_indices }
21
21
 
22
22
  subject { described_class.new(index, to_index: to_index, delete: delete, fields: fields) }
23
23
  let(:index) { CitiesIndex }
@@ -216,7 +216,7 @@ describe Chewy::Index::Import::BulkBuilder do
216
216
  end
217
217
 
218
218
  def do_raw_index_comment(options:, data:)
219
- CommentsIndex.client.index(options.merge(index: 'comments', type: '_doc', refresh: true, body: data))
219
+ CommentsIndex.client.index(options.merge(index: 'comments', refresh: true, body: data))
220
220
  end
221
221
 
222
222
  def raw_index_comment(comment)
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Chewy::Index::Import::BulkRequest do
4
- before { Chewy.massacre }
4
+ before { drop_indices }
5
5
 
6
6
  subject { described_class.new(index, suffix: suffix, bulk_size: bulk_size, **bulk_options) }
7
7
  let(:suffix) {}
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  # TODO: add more specs here later
4
4
  describe Chewy::Index::Import::Routine do
5
- before { Chewy.massacre }
5
+ before { drop_indices }
6
6
  before do
7
7
  stub_index(:cities) do
8
8
  field :name
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Chewy::Index::Import do
4
- before { Chewy.massacre }
4
+ before { drop_indices }
5
5
 
6
6
  before do
7
7
  stub_model(:city)
@@ -204,10 +204,10 @@ describe Chewy::Index::Import do
204
204
  end
205
205
  end
206
206
 
207
- let(:mapper_parsing_exception) do
207
+ let(:document_parsing_exception) do
208
208
  {
209
- 'type' => 'mapper_parsing_exception',
210
- 'reason' => 'object mapping for [name] tried to parse field [name] as object, but found a concrete value'
209
+ 'type' => 'document_parsing_exception',
210
+ 'reason' => '[1:9] object mapping for [name] tried to parse field [name] as object, but found a concrete value'
211
211
  }
212
212
  end
213
213
 
@@ -215,7 +215,7 @@ describe Chewy::Index::Import do
215
215
  payload = subscribe_notification
216
216
  import dummy_cities, batch_size: 2
217
217
  expect(payload).to eq(index: CitiesIndex,
218
- errors: {index: {mapper_parsing_exception => %w[1 2 3]}},
218
+ errors: {index: {document_parsing_exception => %w[1 2 3]}},
219
219
  import: {index: 3})
220
220
  end
221
221
  end
@@ -270,8 +270,8 @@ describe Chewy::Index::Import do
270
270
  expect(payload).to eq(
271
271
  errors: {
272
272
  index: {{
273
- 'type' => 'mapper_parsing_exception',
274
- 'reason' => 'object mapping for [object] tried to parse field [object] as object, but found a concrete value'
273
+ 'type' => 'document_parsing_exception',
274
+ 'reason' => '[1:27] object mapping for [object] tried to parse field [object] as object, but found a concrete value'
275
275
  } => %w[2 4]}
276
276
  },
277
277
  import: {index: 6},
@@ -293,8 +293,8 @@ describe Chewy::Index::Import do
293
293
  expect(payload).to eq(
294
294
  errors: {
295
295
  index: {{
296
- 'type' => 'mapper_parsing_exception',
297
- 'reason' => 'object mapping for [object] tried to parse field [object] as object, but found a concrete value'
296
+ 'type' => 'document_parsing_exception',
297
+ 'reason' => '[1:27] object mapping for [object] tried to parse field [object] as object, but found a concrete value'
298
298
  } => %w[2 4]}
299
299
  },
300
300
  import: {index: 6},
@@ -319,8 +319,8 @@ describe Chewy::Index::Import do
319
319
  expect(payload).to eq(
320
320
  errors: {
321
321
  index: {{
322
- 'type' => 'mapper_parsing_exception',
323
- 'reason' => 'object mapping for [object] tried to parse field [object] as object, but found a concrete value'
322
+ 'type' => 'document_parsing_exception',
323
+ 'reason' => '[1:27] object mapping for [object] tried to parse field [object] as object, but found a concrete value'
324
324
  } => %w[2 4]}
325
325
  },
326
326
  import: {index: 6},
@@ -383,8 +383,8 @@ describe Chewy::Index::Import do
383
383
 
384
384
  # Full match doesn't work here.
385
385
  expect(payload[:errors][:update].keys).to match([
386
- hash_including('type' => 'document_missing_exception', 'reason' => '[_doc][1]: document missing'),
387
- hash_including('type' => 'document_missing_exception', 'reason' => '[_doc][3]: document missing')
386
+ hash_including('type' => 'document_missing_exception', 'reason' => '[1]: document missing'),
387
+ hash_including('type' => 'document_missing_exception', 'reason' => '[3]: document missing')
388
388
  ])
389
389
  expect(payload[:errors][:update].values).to eq([['1'], ['3']])
390
390
  expect(imported_cities).to match_array([
@@ -431,8 +431,8 @@ describe Chewy::Index::Import do
431
431
  expect(payload).to eq(
432
432
  errors: {
433
433
  update: {{
434
- 'type' => 'mapper_parsing_exception',
435
- 'reason' => 'object mapping for [object] tried to parse field [object] as object, but found a concrete value'
434
+ 'type' => 'document_parsing_exception',
435
+ 'reason' => '[1:26] object mapping for [object] tried to parse field [object] as object, but found a concrete value'
436
436
  } => %w[2 4]}
437
437
  },
438
438
  import: {index: 6},
@@ -21,7 +21,7 @@ describe Chewy::Index::Observe::Callback do
21
21
  end
22
22
 
23
23
  context 'when executable is has arity 1' do
24
- let(:executable) { ->(record) { record.population } }
24
+ let(:executable) { lambda(&:population) }
25
25
 
26
26
  it 'calls exectuable within context' do
27
27
  expect(callback.call(city)).to eq(city.population)
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Chewy::Index::Specification do
4
- before { Chewy.massacre }
4
+ before { drop_indices }
5
5
 
6
6
  let(:index1) do
7
7
  stub_index(:places) do
@@ -46,7 +46,6 @@ describe Chewy::Index::Specification do
46
46
  specify do
47
47
  expect { specification1.lock! }.to change { Chewy::Stash::Specification.all.hits }.from([]).to([{
48
48
  '_index' => 'chewy_specifications',
49
- '_type' => '_doc',
50
49
  '_id' => 'places',
51
50
  '_score' => 1.0,
52
51
  '_source' => {'specification' => Base64.encode64({
@@ -62,7 +61,6 @@ describe Chewy::Index::Specification do
62
61
  specify do
63
62
  expect { specification5.lock! }.to change { Chewy::Stash::Specification.all.hits }.to([{
64
63
  '_index' => 'chewy_specifications',
65
- '_type' => '_doc',
66
64
  '_id' => 'places',
67
65
  '_score' => 1.0,
68
66
  '_source' => {'specification' => Base64.encode64({
@@ -71,7 +69,6 @@ describe Chewy::Index::Specification do
71
69
  }.to_json)}
72
70
  }, {
73
71
  '_index' => 'chewy_specifications',
74
- '_type' => '_doc',
75
72
  '_id' => 'namespace/cities',
76
73
  '_score' => 1.0,
77
74
  '_source' => {'specification' => Base64.encode64({
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Chewy::Index::Syncer, :orm do
4
- before { Chewy.massacre }
4
+ before { drop_indices }
5
5
  before do
6
6
  stub_model(:city)
7
7
  stub_index(:cities) do
@@ -177,7 +177,7 @@ describe Chewy::Index do
177
177
 
178
178
  context do
179
179
  before do
180
- Chewy.massacre
180
+ drop_indices
181
181
  PlacesIndex.import!(
182
182
  double(colors: ['red']),
183
183
  double(colors: %w[red green]),
@@ -21,7 +21,7 @@ describe Chewy::Journal do
21
21
  default_import_options journal: true
22
22
  end
23
23
 
24
- Chewy.massacre
24
+ drop_indices
25
25
  Chewy.settings[:prefix] = 'some_prefix'
26
26
  Timecop.freeze(time)
27
27
  end
@@ -145,7 +145,7 @@ describe Chewy::Journal do
145
145
  end
146
146
 
147
147
  context do
148
- before { Chewy.massacre }
148
+ before { drop_indices }
149
149
  before do
150
150
  stub_model(:city) do
151
151
  update_index 'cities', :self
@@ -17,7 +17,7 @@ describe :minitest_helper do
17
17
  end
18
18
 
19
19
  before do
20
- Chewy.massacre
20
+ drop_indices
21
21
  end
22
22
 
23
23
  before do
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
  require 'chewy/multi_search'
3
3
 
4
4
  describe Chewy::MultiSearch do
5
- before { Chewy.massacre }
5
+ before { drop_indices }
6
6
 
7
7
  before do
8
8
  stub_model(:city)
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
  require 'rake'
3
3
 
4
4
  describe Chewy::RakeHelper, :orm do
5
- before { Chewy.massacre }
5
+ before { drop_indices }
6
6
 
7
7
  before do
8
8
  described_class.instance_variable_set(:@journal_exists, journal_exists)
@@ -9,7 +9,7 @@ describe :update_index do
9
9
  end
10
10
 
11
11
  before do
12
- Chewy.massacre
12
+ drop_indices
13
13
  DummiesIndex.create!
14
14
  end
15
15
 
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  describe Chewy::Runtime do
4
4
  describe '.version' do
5
5
  specify { expect(described_class.version).to be_a(described_class::Version) }
6
- specify { expect(described_class.version).to be >= '7.0' }
7
- specify { expect(described_class.version).to be < '8.0' }
6
+ specify { expect(described_class.version).to be >= '8.0' }
7
+ specify { expect(described_class.version).to be < '9.0' }
8
8
  end
9
9
  end
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Chewy::Search::Loader do
4
- before { Chewy.massacre }
4
+ before { drop_indices }
5
5
 
6
6
  before do
7
7
  stub_model(:city)
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  shared_examples :kaminari do |request_base_class|
4
- before { Chewy.massacre }
4
+ before { drop_indices }
5
5
 
6
6
  before do
7
7
  stub_index(:products) do
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Chewy::Search::Request do
4
- before { Chewy.massacre }
4
+ before { drop_indices }
5
5
 
6
6
  before do
7
7
  stub_index(:products) do
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Chewy::Search::Response, :orm do
4
- before { Chewy.massacre }
4
+ before { drop_indices }
5
5
 
6
6
  before do
7
7
  stub_model(:city)
@@ -39,7 +39,7 @@ describe Chewy::Search::Response, :orm do
39
39
  specify { expect(subject.hits).to all be_a(Hash) }
40
40
  specify do
41
41
  expect(subject.hits.flat_map(&:keys).uniq)
42
- .to match_array(%w[_id _index _type _score _source sort])
42
+ .to match_array(%w[_id _index _score _source sort])
43
43
  end
44
44
 
45
45
  context do
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Chewy::Search::Scrolling, :orm do
4
- before { Chewy.massacre }
4
+ before { drop_indices }
5
5
 
6
6
  before do
7
7
  stub_model(:city)
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Chewy::Search do
4
- before { Chewy.massacre }
4
+ before { drop_indices }
5
5
 
6
6
  before do
7
7
  stub_index(:products)
@@ -5,7 +5,7 @@ describe Chewy::Stash::Journal, :orm do
5
5
  response['deleted'] || response['_indices']['_all']['deleted']
6
6
  end
7
7
 
8
- before { Chewy.massacre }
8
+ before { drop_indices }
9
9
 
10
10
  before do
11
11
  stub_model(:city)
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  if defined?(Sidekiq)
4
4
  require 'sidekiq/testing'
5
- require 'mock_redis'
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 = MockRedis.new
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' => (Time.current.to_i.ceil(-1) + 2.seconds).to_i,
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([other_city.id, city.id]).once
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([other_city.id, city.id]).once
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([other_city.id, city.id], update_fields: %w[description name]).once
137
+ expect(CitiesIndex).to receive(:import!).with(match_array([city.id, other_city.id]), update_fields: match_array(%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'])
@@ -1,7 +1,7 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Chewy::Strategy do
4
- before { Chewy.massacre }
4
+ before { drop_indices }
5
5
  subject(:strategy) { Chewy::Strategy.new }
6
6
 
7
7
  describe '#current' do
data/spec/chewy_spec.rb CHANGED
@@ -31,8 +31,8 @@ describe Chewy do
31
31
  end
32
32
  end
33
33
 
34
- describe '.massacre' do
35
- before { Chewy.massacre }
34
+ xdescribe '.massacre' do
35
+ before { drop_indices }
36
36
 
37
37
  before do
38
38
  allow(Chewy).to receive_messages(configuration: Chewy.configuration.merge(prefix: 'prefix1'))
@@ -40,7 +40,7 @@ describe Chewy do
40
40
  allow(Chewy).to receive_messages(configuration: Chewy.configuration.merge(prefix: 'prefix2'))
41
41
  stub_index(:developers).create!
42
42
 
43
- Chewy.massacre
43
+ drop_indices
44
44
 
45
45
  allow(Chewy).to receive_messages(configuration: Chewy.configuration.merge(prefix: 'prefix1'))
46
46
  end
@@ -84,7 +84,8 @@ describe Chewy do
84
84
  # To avoid flaky issues when previous specs were run
85
85
  allow(Chewy::Index).to receive(:descendants).and_return([CitiesIndex, PlacesIndex])
86
86
 
87
- Chewy.massacre
87
+ CitiesIndex.delete
88
+ PlacesIndex.delete
88
89
  end
89
90
 
90
91
  specify do
@@ -111,7 +112,7 @@ describe Chewy do
111
112
  expect(CitiesIndex.exists?).to eq true
112
113
  expect(PlacesIndex.exists?).to eq true
113
114
 
114
- expect { Chewy.create_indices! }.to raise_error(Elasticsearch::Transport::Transport::Errors::BadRequest)
115
+ expect { Chewy.create_indices! }.to raise_error(Elastic::Transport::Transport::Errors::BadRequest)
115
116
  end
116
117
  end
117
118
  end
data/spec/spec_helper.rb CHANGED
@@ -28,6 +28,32 @@ Chewy.settings = {
28
28
  }
29
29
  }
30
30
 
31
+ # To work with security enabled:
32
+ #
33
+ # user = ENV['ES_USER'] || 'elastic'
34
+ # password = ENV['ES_PASSWORD'] || ''
35
+ # ca_cert = ENV['ES_CA_CERT'] || './tmp/http_ca.crt'
36
+ #
37
+ # Chewy.settings.merge!(
38
+ # user: user,
39
+ # password: password,
40
+ # transport_options: {
41
+ # ssl: {
42
+ # ca_file: ca_cert
43
+ # }
44
+ # }
45
+ # )
46
+
47
+ # Low-level substitute for now-obsolete drop_indices
48
+ def drop_indices
49
+ response = Chewy.client.cat.indices
50
+ indices = response.body.lines.map { |line| line.split[2] }
51
+ return if indices.blank?
52
+
53
+ Chewy.client.indices.delete(index: indices)
54
+ Chewy.wait_for_status
55
+ end
56
+
31
57
  # Chewy.transport_logger = Logger.new(STDERR)
32
58
 
33
59
  RSpec.configure do |config|
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.5.1
4
+ version: 8.0.0.pre.beta
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-01-30 00:00:00.000000000 Z
12
+ date: 2024-09-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activesupport
@@ -17,34 +17,34 @@ dependencies:
17
17
  requirements:
18
18
  - - ">="
19
19
  - !ruby/object:Gem::Version
20
- version: '5.2'
20
+ version: '6.1'
21
21
  type: :runtime
22
22
  prerelease: false
23
23
  version_requirements: !ruby/object:Gem::Requirement
24
24
  requirements:
25
25
  - - ">="
26
26
  - !ruby/object:Gem::Version
27
- version: '5.2'
27
+ version: '6.1'
28
28
  - !ruby/object:Gem::Dependency
29
29
  name: elasticsearch
30
30
  requirement: !ruby/object:Gem::Requirement
31
31
  requirements:
32
32
  - - ">="
33
33
  - !ruby/object:Gem::Version
34
- version: 7.12.0
34
+ version: '8.14'
35
35
  - - "<"
36
36
  - !ruby/object:Gem::Version
37
- version: 7.14.0
37
+ version: '9.0'
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.12.0
44
+ version: '8.14'
45
45
  - - "<"
46
46
  - !ruby/object:Gem::Version
47
- version: 7.14.0
47
+ version: '9.0'
48
48
  - !ruby/object:Gem::Dependency
49
49
  name: elasticsearch-dsl
50
50
  requirement: !ruby/object:Gem::Requirement
@@ -88,6 +88,7 @@ files:
88
88
  - README.md
89
89
  - Rakefile
90
90
  - chewy.gemspec
91
+ - docker-compose.yml
91
92
  - filters
92
93
  - gemfiles/base.gemfile
93
94
  - gemfiles/rails.6.1.activerecord.gemfile
@@ -311,16 +312,16 @@ require_paths:
311
312
  - lib
312
313
  required_ruby_version: !ruby/object:Gem::Requirement
313
314
  requirements:
314
- - - ">="
315
+ - - "~>"
315
316
  - !ruby/object:Gem::Version
316
- version: '0'
317
+ version: '3.0'
317
318
  required_rubygems_version: !ruby/object:Gem::Requirement
318
319
  requirements:
319
- - - ">="
320
+ - - ">"
320
321
  - !ruby/object:Gem::Version
321
- version: '0'
322
+ version: 1.3.1
322
323
  requirements: []
323
- rubygems_version: 3.2.33
324
+ rubygems_version: 3.4.10
324
325
  signing_key:
325
326
  specification_version: 4
326
327
  summary: Elasticsearch ODM client wrapper