chewy 8.3.1 → 8.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -1
- data/README.md +17 -0
- data/lib/chewy/elastic_client.rb +15 -0
- data/lib/chewy/index/import/bulk_builder.rb +1 -1
- data/lib/chewy/strategy/delayed_sidekiq/redis_script.rb +37 -0
- data/lib/chewy/strategy/delayed_sidekiq/scheduler.rb +2 -1
- data/lib/chewy/strategy/delayed_sidekiq/worker.rb +1 -1
- data/lib/chewy/version.rb +1 -1
- data/lib/chewy.rb +15 -0
- metadata +3 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bbef8e814a251ebcf189865c37c82476a8e3397983c4ede20694df87a7a61bd9
|
|
4
|
+
data.tar.gz: e673c1ab4ae490dd3ae716bcb3e617a0661f87c3f43143f59237a46228777375
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: '04927525ee47f4f5591ed3f826d2477a87f267be465b739070c82cf1c54d558fe77d56bc88868d35be5fa6c27c8a0302ac31b6fd1f7c79c18b0759eb3e14eabf'
|
|
7
|
+
data.tar.gz: 62c30c3643ed78e661409929e5a075f02cbac789978f84d0a89531e00ab90764782dc085a7a44243b53b5613466794baa4b881eb22c55abdbde7b46bbb583966
|
data/CHANGELOG.md
CHANGED
|
@@ -8,7 +8,19 @@
|
|
|
8
8
|
|
|
9
9
|
### Changes
|
|
10
10
|
|
|
11
|
-
## 8.
|
|
11
|
+
## 8.4.0 (2026-06-17)
|
|
12
|
+
|
|
13
|
+
### New Features
|
|
14
|
+
|
|
15
|
+
* [#1036](https://github.com/toptal/chewy/issues/1036): Add `Chewy.close_client` and `Chewy::ElasticClient#close` to explicitly close connections to Elasticsearch, avoiding file descriptor leaks in long-lived multi-threaded processes (e.g. Sidekiq). ([@AlfonsoUceda][])
|
|
16
|
+
|
|
17
|
+
### Bug Fixes
|
|
18
|
+
|
|
19
|
+
* ([#1034](https://github.com/toptal/chewy/issues/1034)): Fixed `delayed_sidekiq` strategy raising `TypeError: Unsupported command argument type: Array` on Sidekiq 7+. The LUA scripts now run via `EVALSHA` through a portable helper instead of redis-rb's keyword `eval`, which the redis-client-backed client Sidekiq 7+ yields does not support. ([@AlfonsoUceda][])
|
|
20
|
+
|
|
21
|
+
### Changes
|
|
22
|
+
|
|
23
|
+
## 8.3.1 (2026-06-05)
|
|
12
24
|
|
|
13
25
|
### New Features
|
|
14
26
|
|
|
@@ -898,6 +910,7 @@
|
|
|
898
910
|
[@AgeevAndrew]: https://github.com/AgeevAndrew
|
|
899
911
|
[@aglushkov]: https://github.com/aglushkov
|
|
900
912
|
[@AlexVPopov]: https://github.com/AlexVPopov
|
|
913
|
+
[@AlfonsoUceda]: https://github.com/AlfonsoUceda
|
|
901
914
|
[@AndreySavelyev]: https://github.com/AndreySavelyev
|
|
902
915
|
[@afg419]: https://github.com/afg419
|
|
903
916
|
[@arion]: https://github.com/arion
|
data/README.md
CHANGED
|
@@ -133,6 +133,23 @@ development:
|
|
|
133
133
|
ca_file: './tmp/http_ca.crt'
|
|
134
134
|
```
|
|
135
135
|
|
|
136
|
+
### Closing connections
|
|
137
|
+
|
|
138
|
+
`Chewy.client` is memoized per thread, so every thread that touches Chewy gets
|
|
139
|
+
its own client with its own connections to Elasticsearch. Neither
|
|
140
|
+
`elasticsearch-ruby` nor `elastic-transport` expose a public way to close those
|
|
141
|
+
connections, so they are only released when Ruby's garbage collector reclaims
|
|
142
|
+
the client. In long-lived, multi-threaded processes that frequently spawn and
|
|
143
|
+
discard threads (e.g. Sidekiq, which replaces a thread on job failure), this can
|
|
144
|
+
leak file descriptors.
|
|
145
|
+
|
|
146
|
+
Use `Chewy.close_client` to close the current thread's connections and drop its
|
|
147
|
+
client. The next `Chewy.client` call rebuilds a fresh one:
|
|
148
|
+
|
|
149
|
+
```ruby
|
|
150
|
+
Chewy.close_client
|
|
151
|
+
```
|
|
152
|
+
|
|
136
153
|
### Index
|
|
137
154
|
|
|
138
155
|
Create `app/chewy/users_index.rb` with User Index:
|
data/lib/chewy/elastic_client.rb
CHANGED
|
@@ -12,6 +12,21 @@ module Chewy
|
|
|
12
12
|
@elastic_client = elastic_client
|
|
13
13
|
end
|
|
14
14
|
|
|
15
|
+
# Closes the underlying connections to Elasticsearch.
|
|
16
|
+
#
|
|
17
|
+
# Neither elasticsearch-ruby nor elastic-transport expose a public method
|
|
18
|
+
# to close connections, so they are only released when Ruby's garbage
|
|
19
|
+
# collector reclaims the client instance. This reaches down to the Faraday
|
|
20
|
+
# connection of every transport connection and closes it explicitly, which
|
|
21
|
+
# is useful to avoid file descriptor leaks in long-lived processes that
|
|
22
|
+
# build a client per thread (e.g. Sidekiq workers).
|
|
23
|
+
def close
|
|
24
|
+
@elastic_client.transport.connections.each do |connection|
|
|
25
|
+
faraday = connection.connection
|
|
26
|
+
faraday.close if faraday.respond_to?(:close)
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
15
30
|
private
|
|
16
31
|
|
|
17
32
|
def method_missing(name, *args, **kwargs, &block)
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Chewy
|
|
4
|
+
class Strategy
|
|
5
|
+
class DelayedSidekiq
|
|
6
|
+
# Runs a LUA script through whatever client `Sidekiq.redis` yields.
|
|
7
|
+
#
|
|
8
|
+
# redis-rb (Sidekiq <= 6) accepts `eval(script, keys:, argv:)`, but the
|
|
9
|
+
# real Sidekiq 7+ runtime yields a redis-client-backed CompatClient that
|
|
10
|
+
# has no `#eval` and forwards the keyword args as a nested array, raising
|
|
11
|
+
# `TypeError: Unsupported command argument type: Array` (issue #971).
|
|
12
|
+
#
|
|
13
|
+
# `evalsha(sha, keys_array, argv_array)` is the one form both clients
|
|
14
|
+
# expand to the flat `EVALSHA sha numkeys *keys *argv` shape, so we load
|
|
15
|
+
# the script once and call it by digest, reloading on NOSCRIPT.
|
|
16
|
+
module RedisScript
|
|
17
|
+
def self.call(redis, script, keys:, argv:)
|
|
18
|
+
reloaded = false
|
|
19
|
+
begin
|
|
20
|
+
shas[script] ||= redis.script(:load, script)
|
|
21
|
+
redis.evalsha(shas[script], keys, argv)
|
|
22
|
+
rescue StandardError => e
|
|
23
|
+
raise if reloaded || !e.message.to_s.include?('NOSCRIPT')
|
|
24
|
+
|
|
25
|
+
reloaded = true
|
|
26
|
+
shas.delete(script) # flushed cache or failover: reload and retry once
|
|
27
|
+
retry
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def self.shas
|
|
32
|
+
@shas ||= {}
|
|
33
|
+
end
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -10,6 +10,7 @@ require_relative '../../index'
|
|
|
10
10
|
module Chewy
|
|
11
11
|
class Strategy
|
|
12
12
|
class DelayedSidekiq
|
|
13
|
+
require_relative 'redis_script'
|
|
13
14
|
require_relative 'worker'
|
|
14
15
|
|
|
15
16
|
LUA_SCRIPT = <<~LUA
|
|
@@ -98,7 +99,7 @@ module Chewy
|
|
|
98
99
|
def postpone
|
|
99
100
|
::Sidekiq.redis do |redis|
|
|
100
101
|
# do the redis stuff in a single command to avoid concurrency issues
|
|
101
|
-
if
|
|
102
|
+
if RedisScript.call(redis, LUA_SCRIPT, keys: [timechunk_key, timechunks_key], argv: [serialize_data, at, ttl])
|
|
102
103
|
::Sidekiq::Client.push(
|
|
103
104
|
'queue' => sidekiq_queue,
|
|
104
105
|
'at' => at + margin,
|
|
@@ -39,7 +39,7 @@ module Chewy
|
|
|
39
39
|
options[:refresh] = !Chewy.disable_refresh_async if Chewy.disable_refresh_async
|
|
40
40
|
|
|
41
41
|
::Sidekiq.redis do |redis|
|
|
42
|
-
members =
|
|
42
|
+
members = RedisScript.call(redis, LUA_SCRIPT, keys: [], argv: [type, score, Scheduler::KEY_PREFIX])
|
|
43
43
|
|
|
44
44
|
# extract ids and fields & do the reset of records
|
|
45
45
|
ids, fields = extract_ids_and_fields(members)
|
data/lib/chewy/version.rb
CHANGED
data/lib/chewy.rb
CHANGED
|
@@ -102,6 +102,21 @@ module Chewy
|
|
|
102
102
|
Chewy.current[:chewy_client] ||= Chewy::ElasticClient.new
|
|
103
103
|
end
|
|
104
104
|
|
|
105
|
+
# Closes the current thread's client connections to Elasticsearch and
|
|
106
|
+
# drops the thread-local client, so the next `Chewy.client` call builds a
|
|
107
|
+
# fresh one.
|
|
108
|
+
#
|
|
109
|
+
# Useful in long-lived multi-threaded processes (e.g. Sidekiq) where the
|
|
110
|
+
# per-thread client would otherwise keep its connections open until the
|
|
111
|
+
# dead thread is garbage collected, leaking file descriptors.
|
|
112
|
+
def close_client
|
|
113
|
+
client = Chewy.current[:chewy_client]
|
|
114
|
+
return unless client
|
|
115
|
+
|
|
116
|
+
client.close
|
|
117
|
+
Chewy.current[:chewy_client] = nil
|
|
118
|
+
end
|
|
119
|
+
|
|
105
120
|
# Sends wait_for_status request to ElasticSearch with status
|
|
106
121
|
# defined in configuration.
|
|
107
122
|
#
|
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: 8.
|
|
4
|
+
version: 8.4.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Toptal, LLC
|
|
@@ -174,6 +174,7 @@ files:
|
|
|
174
174
|
- lib/chewy/strategy/base.rb
|
|
175
175
|
- lib/chewy/strategy/bypass.rb
|
|
176
176
|
- lib/chewy/strategy/delayed_sidekiq.rb
|
|
177
|
+
- lib/chewy/strategy/delayed_sidekiq/redis_script.rb
|
|
177
178
|
- lib/chewy/strategy/delayed_sidekiq/scheduler.rb
|
|
178
179
|
- lib/chewy/strategy/delayed_sidekiq/worker.rb
|
|
179
180
|
- lib/chewy/strategy/lazy_sidekiq.rb
|
|
@@ -202,7 +203,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
202
203
|
- !ruby/object:Gem::Version
|
|
203
204
|
version: '0'
|
|
204
205
|
requirements: []
|
|
205
|
-
rubygems_version: 4.0.
|
|
206
|
+
rubygems_version: 4.0.14
|
|
206
207
|
specification_version: 4
|
|
207
208
|
summary: Elasticsearch ODM client wrapper
|
|
208
209
|
test_files: []
|