dalli 4.3.0 → 4.3.2
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 +49 -0
- data/Gemfile +4 -0
- data/lib/dalli/client.rb +38 -19
- data/lib/dalli/instrumentation.rb +26 -24
- data/lib/dalli/key_manager.rb +1 -1
- data/lib/dalli/pipelined_getter.rb +2 -2
- data/lib/dalli/pipelined_setter.rb +1 -1
- data/lib/dalli/protocol/connection_manager.rb +1 -1
- data/lib/dalli/socket.rb +17 -8
- data/lib/dalli/version.rb +1 -1
- data/lib/dalli.rb +3 -0
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7eda4c85eb715e06ef3d8b34ea8e33a3cde89f19379a758f105363457451a034
|
|
4
|
+
data.tar.gz: 36ae8b603f8f778edbbf3bed9b7504ff1a440382bf5520423f49c39961f04a55
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b9a37ecfc73734a141979a34f2e155baa40cea5b22b016c192514c9d5847335d949ee642620c4508cc2ec8a2ceeb4dcec381715e633893623c42454975999d1a
|
|
7
|
+
data.tar.gz: 2a5f38c78c371e0710354a2b915a074512a87225f33fca95c9088ded76cad0dfc22e454fc9f64bddd40d8b0c0a6ab65bb108f467cd5b2b2c39d651285665f845
|
data/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,55 @@
|
|
|
1
1
|
Dalli Changelog
|
|
2
2
|
=====================
|
|
3
3
|
|
|
4
|
+
4.3.2
|
|
5
|
+
==========
|
|
6
|
+
|
|
7
|
+
OpenTelemetry:
|
|
8
|
+
|
|
9
|
+
- Migrate to stable OTel semantic conventions
|
|
10
|
+
- `db.system` renamed to `db.system.name`
|
|
11
|
+
- `db.operation` renamed to `db.operation.name`
|
|
12
|
+
- `server.address` now contains hostname only; `server.port` is a separate integer attribute
|
|
13
|
+
- `get_with_metadata` and `fetch_with_lock` now include `server.address`/`server.port`
|
|
14
|
+
- Add `db.query.text` span attribute with configurable modes
|
|
15
|
+
- `:otel_db_statement` option: `:include`, `:obfuscate`, or `nil` (default: omitted)
|
|
16
|
+
- Add `peer.service` span attribute
|
|
17
|
+
- `:otel_peer_service` option for logical service naming
|
|
18
|
+
|
|
19
|
+
4.3.1
|
|
20
|
+
==========
|
|
21
|
+
|
|
22
|
+
Bug Fixes:
|
|
23
|
+
|
|
24
|
+
- Fix socket compatibility with gems that monkey-patch TCPSocket (#996, #1012)
|
|
25
|
+
- Gems like `socksify` and `resolv-replace` modify `TCPSocket#initialize`, breaking Ruby 3.0+'s `connect_timeout:` keyword argument
|
|
26
|
+
- Detection now uses parameter signature checking instead of gem-specific method detection
|
|
27
|
+
- Falls back to `Timeout.timeout` when monkey-patching is detected
|
|
28
|
+
- Detection result is cached for performance
|
|
29
|
+
|
|
30
|
+
- Fix network retry bug with `socket_max_failures: 0` (#1065)
|
|
31
|
+
- Previously, setting `socket_max_failures: 0` could still cause retries due to error handling
|
|
32
|
+
- Introduced `RetryableNetworkError` subclass to distinguish retryable vs non-retryable errors
|
|
33
|
+
- `down!` now raises non-retryable `NetworkError`, `reconnect!` raises `RetryableNetworkError`
|
|
34
|
+
- Thanks to Graham Cooper (Shopify) for this fix
|
|
35
|
+
|
|
36
|
+
- Fix "character class has duplicated range" Ruby warning (#1067)
|
|
37
|
+
- Fixed regex in `KeyManager::VALID_NAMESPACE_SEPARATORS` that caused warnings on newer Ruby versions
|
|
38
|
+
- Thanks to Hartley McGuire for this fix
|
|
39
|
+
|
|
40
|
+
Improvements:
|
|
41
|
+
|
|
42
|
+
- Add StrictWarnings test helper to catch Ruby warnings early (#1067)
|
|
43
|
+
|
|
44
|
+
- Use bulk attribute setter for OpenTelemetry spans (#1068)
|
|
45
|
+
- Reduces lock acquisitions when setting span attributes
|
|
46
|
+
- Thanks to Robert Laurin (Shopify) for this optimization
|
|
47
|
+
|
|
48
|
+
- Fix double recording of exceptions on OpenTelemetry spans (#1069)
|
|
49
|
+
- OpenTelemetry's `in_span` method already records exceptions and sets error status automatically
|
|
50
|
+
- Removed redundant explicit exception recording that caused exceptions to appear twice in traces
|
|
51
|
+
- Thanks to Robert Laurin (Shopify) for this fix
|
|
52
|
+
|
|
4
53
|
4.3.0
|
|
5
54
|
==========
|
|
6
55
|
|
data/Gemfile
CHANGED
data/lib/dalli/client.rb
CHANGED
|
@@ -50,6 +50,10 @@ module Dalli
|
|
|
50
50
|
# useful for injecting a FIPS compliant hash object.
|
|
51
51
|
# - :protocol - one of either :binary or :meta, defaulting to :binary. This sets the protocol that Dalli uses
|
|
52
52
|
# to communicate with memcached.
|
|
53
|
+
# - :otel_db_statement - controls the +db.query.text+ span attribute when OpenTelemetry is loaded.
|
|
54
|
+
# +:include+ logs the full operation and key(s), +:obfuscate+ replaces keys with "?",
|
|
55
|
+
# +nil+ (default) omits the attribute entirely.
|
|
56
|
+
# - :otel_peer_service - when set, adds a +peer.service+ span attribute with this value for logical service naming.
|
|
53
57
|
#
|
|
54
58
|
def initialize(servers = nil, options = {})
|
|
55
59
|
@normalized_servers = ::Dalli::ServersArgNormalizer.normalize_servers(servers)
|
|
@@ -134,8 +138,8 @@ module Dalli
|
|
|
134
138
|
key = key.to_s
|
|
135
139
|
key = @key_manager.validate_key(key)
|
|
136
140
|
|
|
137
|
-
|
|
138
|
-
|
|
141
|
+
server = ring.server_for_key(key)
|
|
142
|
+
Instrumentation.trace('get_with_metadata', trace_attrs('get_with_metadata', key, server)) do
|
|
139
143
|
server.request(:meta_get, key, options)
|
|
140
144
|
end
|
|
141
145
|
rescue NetworkError => e
|
|
@@ -237,7 +241,8 @@ module Dalli
|
|
|
237
241
|
key = key.to_s
|
|
238
242
|
key = @key_manager.validate_key(key)
|
|
239
243
|
|
|
240
|
-
|
|
244
|
+
server = ring.server_for_key(key)
|
|
245
|
+
Instrumentation.trace('fetch_with_lock', trace_attrs('fetch_with_lock', key, server)) do
|
|
241
246
|
fetch_with_lock_request(key, ttl, lock_ttl, recache_threshold, req_options, &block)
|
|
242
247
|
end
|
|
243
248
|
rescue NetworkError => e
|
|
@@ -318,10 +323,7 @@ module Dalli
|
|
|
318
323
|
def set_multi(hash, ttl = nil, req_options = nil)
|
|
319
324
|
return if hash.empty?
|
|
320
325
|
|
|
321
|
-
Instrumentation.trace('set_multi',
|
|
322
|
-
'db.operation' => 'set_multi',
|
|
323
|
-
'db.memcached.key_count' => hash.size
|
|
324
|
-
}) do
|
|
326
|
+
Instrumentation.trace('set_multi', multi_trace_attrs('set_multi', hash.size, hash.keys)) do
|
|
325
327
|
pipelined_setter.process(hash, ttl_or_default(ttl), req_options)
|
|
326
328
|
end
|
|
327
329
|
end
|
|
@@ -378,10 +380,7 @@ module Dalli
|
|
|
378
380
|
def delete_multi(keys)
|
|
379
381
|
return if keys.empty?
|
|
380
382
|
|
|
381
|
-
Instrumentation.trace('delete_multi',
|
|
382
|
-
'db.operation' => 'delete_multi',
|
|
383
|
-
'db.memcached.key_count' => keys.size
|
|
384
|
-
}) do
|
|
383
|
+
Instrumentation.trace('delete_multi', multi_trace_attrs('delete_multi', keys.size, keys)) do
|
|
385
384
|
pipelined_deleter.process(keys)
|
|
386
385
|
end
|
|
387
386
|
end
|
|
@@ -522,8 +521,8 @@ module Dalli
|
|
|
522
521
|
def record_hit_miss_metrics(span, key_count, hit_count)
|
|
523
522
|
return unless span
|
|
524
523
|
|
|
525
|
-
span.
|
|
526
|
-
|
|
524
|
+
span.add_attributes('db.memcached.hit_count' => hit_count,
|
|
525
|
+
'db.memcached.miss_count' => key_count - hit_count)
|
|
527
526
|
end
|
|
528
527
|
|
|
529
528
|
def get_multi_yielding(keys)
|
|
@@ -548,7 +547,30 @@ module Dalli
|
|
|
548
547
|
end
|
|
549
548
|
|
|
550
549
|
def get_multi_attributes(keys)
|
|
551
|
-
|
|
550
|
+
multi_trace_attrs('get_multi', keys.size, keys)
|
|
551
|
+
end
|
|
552
|
+
|
|
553
|
+
def trace_attrs(operation, key, server)
|
|
554
|
+
attrs = { 'db.operation.name' => operation, 'server.address' => server.hostname }
|
|
555
|
+
attrs['server.port'] = server.port if server.socket_type == :tcp
|
|
556
|
+
attrs['peer.service'] = @options[:otel_peer_service] if @options[:otel_peer_service]
|
|
557
|
+
add_query_text(attrs, operation, key)
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
def multi_trace_attrs(operation, key_count, keys)
|
|
561
|
+
attrs = { 'db.operation.name' => operation, 'db.memcached.key_count' => key_count }
|
|
562
|
+
attrs['peer.service'] = @options[:otel_peer_service] if @options[:otel_peer_service]
|
|
563
|
+
add_query_text(attrs, operation, keys)
|
|
564
|
+
end
|
|
565
|
+
|
|
566
|
+
def add_query_text(attrs, operation, key_or_keys)
|
|
567
|
+
case @options[:otel_db_statement]
|
|
568
|
+
when :include
|
|
569
|
+
attrs['db.query.text'] = "#{operation} #{Array(key_or_keys).join(' ')}"
|
|
570
|
+
when :obfuscate
|
|
571
|
+
attrs['db.query.text'] = "#{operation} ?"
|
|
572
|
+
end
|
|
573
|
+
attrs
|
|
552
574
|
end
|
|
553
575
|
|
|
554
576
|
def check_positive!(amt)
|
|
@@ -616,13 +638,10 @@ module Dalli
|
|
|
616
638
|
key = @key_manager.validate_key(key)
|
|
617
639
|
|
|
618
640
|
server = ring.server_for_key(key)
|
|
619
|
-
Instrumentation.trace(op.to_s,
|
|
620
|
-
'db.operation' => op.to_s,
|
|
621
|
-
'server.address' => server.name
|
|
622
|
-
}) do
|
|
641
|
+
Instrumentation.trace(op.to_s, trace_attrs(op.to_s, key, server)) do
|
|
623
642
|
server.request(op, key, *args)
|
|
624
643
|
end
|
|
625
|
-
rescue
|
|
644
|
+
rescue RetryableNetworkError => e
|
|
626
645
|
Dalli.logger.debug { e.inspect }
|
|
627
646
|
Dalli.logger.debug { 'retrying request with new server' }
|
|
628
647
|
retry
|
|
@@ -8,25 +8,36 @@ module Dalli
|
|
|
8
8
|
# When OpenTelemetry is loaded, Dalli automatically creates spans for cache operations.
|
|
9
9
|
# When OpenTelemetry is not available, all tracing methods are no-ops with zero overhead.
|
|
10
10
|
#
|
|
11
|
+
# Dalli 4.3.2 uses the stable OTel semantic conventions for database spans.
|
|
12
|
+
#
|
|
11
13
|
# == Span Attributes
|
|
12
14
|
#
|
|
13
15
|
# All spans include the following default attributes:
|
|
14
|
-
# - +db.system+ - Always "memcached"
|
|
16
|
+
# - +db.system.name+ - Always "memcached"
|
|
15
17
|
#
|
|
16
18
|
# Single-key operations (+get+, +set+, +delete+, +incr+, +decr+, etc.) add:
|
|
17
|
-
# - +db.operation+ - The operation name (e.g., "get", "set")
|
|
18
|
-
# - +server.address+ - The
|
|
19
|
+
# - +db.operation.name+ - The operation name (e.g., "get", "set")
|
|
20
|
+
# - +server.address+ - The server hostname (e.g., "localhost")
|
|
21
|
+
# - +server.port+ - The server port as an integer (e.g., 11211); omitted for Unix sockets
|
|
19
22
|
#
|
|
20
23
|
# Multi-key operations (+get_multi+) add:
|
|
21
|
-
# - +db.operation+ - "get_multi"
|
|
24
|
+
# - +db.operation.name+ - "get_multi"
|
|
22
25
|
# - +db.memcached.key_count+ - Number of keys requested
|
|
23
26
|
# - +db.memcached.hit_count+ - Number of keys found in cache
|
|
24
27
|
# - +db.memcached.miss_count+ - Number of keys not found
|
|
25
28
|
#
|
|
26
29
|
# Bulk write operations (+set_multi+, +delete_multi+) add:
|
|
27
|
-
# - +db.operation+ - The operation name
|
|
30
|
+
# - +db.operation.name+ - The operation name
|
|
28
31
|
# - +db.memcached.key_count+ - Number of keys in the operation
|
|
29
32
|
#
|
|
33
|
+
# == Optional Attributes
|
|
34
|
+
#
|
|
35
|
+
# - +db.query.text+ - The operation and key(s), controlled by the +:otel_db_statement+ client option:
|
|
36
|
+
# - +:include+ - Full text (e.g., "get mykey")
|
|
37
|
+
# - +:obfuscate+ - Obfuscated (e.g., "get ?")
|
|
38
|
+
# - +nil+ (default) - Attribute omitted
|
|
39
|
+
# - +peer.service+ - Logical service name, set via the +:otel_peer_service+ client option
|
|
40
|
+
#
|
|
30
41
|
# == Error Handling
|
|
31
42
|
#
|
|
32
43
|
# When an exception occurs during a traced operation:
|
|
@@ -40,8 +51,8 @@ module Dalli
|
|
|
40
51
|
##
|
|
41
52
|
module Instrumentation
|
|
42
53
|
# Default attributes included on all memcached spans.
|
|
43
|
-
# @return [Hash] frozen hash with 'db.system' => 'memcached'
|
|
44
|
-
DEFAULT_ATTRIBUTES = { 'db.system' => 'memcached' }.freeze
|
|
54
|
+
# @return [Hash] frozen hash with 'db.system.name' => 'memcached'
|
|
55
|
+
DEFAULT_ATTRIBUTES = { 'db.system.name' => 'memcached' }.freeze
|
|
45
56
|
|
|
46
57
|
class << self
|
|
47
58
|
# Returns the OpenTelemetry tracer if available, nil otherwise.
|
|
@@ -75,27 +86,24 @@ module Dalli
|
|
|
75
86
|
# @param name [String] the span name (e.g., 'get', 'set', 'delete')
|
|
76
87
|
# @param attributes [Hash] span attributes to merge with defaults.
|
|
77
88
|
# Common attributes include:
|
|
78
|
-
# - 'db.operation' - the operation name
|
|
79
|
-
# - 'server.address' - the
|
|
89
|
+
# - 'db.operation.name' - the operation name
|
|
90
|
+
# - 'server.address' - the server hostname
|
|
91
|
+
# - 'server.port' - the server port (integer)
|
|
80
92
|
# - 'db.memcached.key_count' - number of keys (for multi operations)
|
|
81
93
|
# @yield the cache operation to trace
|
|
82
94
|
# @return [Object] the result of the block
|
|
83
95
|
# @raise [StandardError] re-raises any exception from the block
|
|
84
96
|
#
|
|
85
97
|
# @example Tracing a set operation
|
|
86
|
-
# trace('set', { 'db.operation' => 'set', 'server.address' => 'localhost
|
|
98
|
+
# trace('set', { 'db.operation.name' => 'set', 'server.address' => 'localhost', 'server.port' => 11211 }) do
|
|
87
99
|
# server.set(key, value, ttl)
|
|
88
100
|
# end
|
|
89
101
|
#
|
|
90
102
|
def trace(name, attributes = {})
|
|
91
103
|
return yield unless enabled?
|
|
92
104
|
|
|
93
|
-
tracer.in_span(name, attributes: DEFAULT_ATTRIBUTES.merge(attributes), kind: :client) do |
|
|
105
|
+
tracer.in_span(name, attributes: DEFAULT_ATTRIBUTES.merge(attributes), kind: :client) do |_span|
|
|
94
106
|
yield
|
|
95
|
-
rescue StandardError => e
|
|
96
|
-
span.record_exception(e)
|
|
97
|
-
span.status = OpenTelemetry::Trace::Status.error(e.message)
|
|
98
|
-
raise
|
|
99
107
|
end
|
|
100
108
|
end
|
|
101
109
|
|
|
@@ -114,7 +122,7 @@ module Dalli
|
|
|
114
122
|
# @raise [StandardError] re-raises any exception from the block
|
|
115
123
|
#
|
|
116
124
|
# @example Recording hit/miss metrics after get_multi
|
|
117
|
-
# trace_with_result('get_multi', { 'db.operation' => 'get_multi' }) do |span|
|
|
125
|
+
# trace_with_result('get_multi', { 'db.operation.name' => 'get_multi' }) do |span|
|
|
118
126
|
# results = fetch_from_cache(keys)
|
|
119
127
|
# if span
|
|
120
128
|
# span.set_attribute('db.memcached.hit_count', results.size)
|
|
@@ -123,16 +131,10 @@ module Dalli
|
|
|
123
131
|
# results
|
|
124
132
|
# end
|
|
125
133
|
#
|
|
126
|
-
def trace_with_result(name, attributes = {})
|
|
134
|
+
def trace_with_result(name, attributes = {}, &)
|
|
127
135
|
return yield(nil) unless enabled?
|
|
128
136
|
|
|
129
|
-
tracer.in_span(name, attributes: DEFAULT_ATTRIBUTES.merge(attributes), kind: :client)
|
|
130
|
-
yield(span)
|
|
131
|
-
rescue StandardError => e
|
|
132
|
-
span.record_exception(e)
|
|
133
|
-
span.status = OpenTelemetry::Trace::Status.error(e.message)
|
|
134
|
-
raise
|
|
135
|
-
end
|
|
137
|
+
tracer.in_span(name, attributes: DEFAULT_ATTRIBUTES.merge(attributes), kind: :client, &)
|
|
136
138
|
end
|
|
137
139
|
end
|
|
138
140
|
end
|
data/lib/dalli/key_manager.rb
CHANGED
|
@@ -31,7 +31,7 @@ module Dalli
|
|
|
31
31
|
|
|
32
32
|
# Valid separators: non-alphanumeric, single printable ASCII characters
|
|
33
33
|
# Excludes: alphanumerics, whitespace, control characters
|
|
34
|
-
VALID_NAMESPACE_SEPARATORS = /\A[^a-zA-Z0-9\
|
|
34
|
+
VALID_NAMESPACE_SEPARATORS = /\A[^a-zA-Z0-9 \x00-\x1F\x7F]\z/
|
|
35
35
|
|
|
36
36
|
def initialize(client_options)
|
|
37
37
|
@key_options =
|
|
@@ -36,7 +36,7 @@ module Dalli
|
|
|
36
36
|
|
|
37
37
|
servers = fetch_responses(servers, start_time, @ring.socket_timeout, &block) until servers.empty?
|
|
38
38
|
end
|
|
39
|
-
rescue
|
|
39
|
+
rescue Dalli::RetryableNetworkError => e
|
|
40
40
|
Dalli.logger.debug { e.inspect }
|
|
41
41
|
Dalli.logger.debug { 'retrying pipelined gets because of timeout' }
|
|
42
42
|
retry
|
|
@@ -143,7 +143,7 @@ module Dalli
|
|
|
143
143
|
servers
|
|
144
144
|
rescue NetworkError
|
|
145
145
|
# Abort and raise if we encountered a network error. This triggers
|
|
146
|
-
# a retry at the top level.
|
|
146
|
+
# a retry at the top level on RetryableNetworkError.
|
|
147
147
|
abort_without_timeout(servers)
|
|
148
148
|
raise
|
|
149
149
|
end
|
|
@@ -28,7 +28,7 @@ module Dalli
|
|
|
28
28
|
servers = setup_requests(hash, ttl, req_options)
|
|
29
29
|
finish_requests(servers)
|
|
30
30
|
end
|
|
31
|
-
rescue
|
|
31
|
+
rescue Dalli::RetryableNetworkError => e
|
|
32
32
|
Dalli.logger.debug { e.inspect }
|
|
33
33
|
Dalli.logger.debug { 'retrying pipelined sets because of network error' }
|
|
34
34
|
retry
|
data/lib/dalli/socket.rb
CHANGED
|
@@ -90,6 +90,12 @@ module Dalli
|
|
|
90
90
|
# options - supports enhanced logging in the case of a timeout
|
|
91
91
|
attr_accessor :options
|
|
92
92
|
|
|
93
|
+
# Expected parameter signature for unmodified TCPSocket#initialize.
|
|
94
|
+
# Used to detect when gems like socksify or resolv-replace have monkey-patched
|
|
95
|
+
# TCPSocket, which breaks the connect_timeout: keyword argument.
|
|
96
|
+
TCPSOCKET_NATIVE_PARAMETERS = [[:rest]].freeze
|
|
97
|
+
private_constant :TCPSOCKET_NATIVE_PARAMETERS
|
|
98
|
+
|
|
93
99
|
def self.open(host, port, options = {})
|
|
94
100
|
create_socket_with_timeout(host, port, options) do |sock|
|
|
95
101
|
sock.options = { host: host, port: port }.merge(options)
|
|
@@ -99,15 +105,18 @@ module Dalli
|
|
|
99
105
|
end
|
|
100
106
|
end
|
|
101
107
|
|
|
108
|
+
# Detect and cache whether TCPSocket supports the connect_timeout: keyword argument.
|
|
109
|
+
# Returns false if TCPSocket#initialize has been monkey-patched by gems like
|
|
110
|
+
# socksify or resolv-replace, which don't support keyword arguments.
|
|
111
|
+
def self.supports_connect_timeout?
|
|
112
|
+
return @supports_connect_timeout if defined?(@supports_connect_timeout)
|
|
113
|
+
|
|
114
|
+
@supports_connect_timeout = RUBY_VERSION >= '3.0' &&
|
|
115
|
+
::TCPSocket.instance_method(:initialize).parameters == TCPSOCKET_NATIVE_PARAMETERS
|
|
116
|
+
end
|
|
117
|
+
|
|
102
118
|
def self.create_socket_with_timeout(host, port, options)
|
|
103
|
-
|
|
104
|
-
# (part of ruby standard library since 3.0.0, should be removed in 3.4.0),
|
|
105
|
-
# as it does not handle keyword arguments correctly.
|
|
106
|
-
# To check this we are using the fact that resolv-replace
|
|
107
|
-
# aliases TCPSocket#initialize method to #original_resolv_initialize.
|
|
108
|
-
# https://github.com/ruby/resolv-replace/blob/v0.1.1/lib/resolv-replace.rb#L21
|
|
109
|
-
if RUBY_VERSION >= '3.0' &&
|
|
110
|
-
!::TCPSocket.private_method_defined?(:original_resolv_initialize)
|
|
119
|
+
if supports_connect_timeout?
|
|
111
120
|
sock = new(host, port, connect_timeout: options[:socket_timeout])
|
|
112
121
|
yield(sock)
|
|
113
122
|
else
|
data/lib/dalli/version.rb
CHANGED
data/lib/dalli.rb
CHANGED
|
@@ -28,6 +28,9 @@ module Dalli
|
|
|
28
28
|
# raised when Memcached response with a SERVER_ERROR
|
|
29
29
|
class ServerError < DalliError; end
|
|
30
30
|
|
|
31
|
+
# socket/server communication error that can be retried
|
|
32
|
+
class RetryableNetworkError < NetworkError; end
|
|
33
|
+
|
|
31
34
|
# Implements the NullObject pattern to store an application-defined value for 'Key not found' responses.
|
|
32
35
|
class NilObject; end # rubocop:disable Lint/EmptyClass
|
|
33
36
|
NOT_FOUND = NilObject.new
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: dalli
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 4.3.
|
|
4
|
+
version: 4.3.2
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Peter M. Goldstein
|
|
@@ -93,7 +93,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
93
93
|
- !ruby/object:Gem::Version
|
|
94
94
|
version: '0'
|
|
95
95
|
requirements: []
|
|
96
|
-
rubygems_version: 4.0.
|
|
96
|
+
rubygems_version: 4.0.6
|
|
97
97
|
specification_version: 4
|
|
98
98
|
summary: High performance memcached client for Ruby
|
|
99
99
|
test_files: []
|