chewy 7.5.1 → 8.0.0.pre.beta

Sign up to get free protection for your applications and to get access to all the features.
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