solid-redis 1.0.3 → 1.0.4
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 +23 -0
- data/README.md +111 -2
- data/lib/solid_redis/client.rb +10 -5
- data/lib/solid_redis/config.rb +2 -1
- data/lib/solid_redis/resp.rb +60 -16
- data/lib/solid_redis/version.rb +1 -1
- metadata +30 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: b6c2088305fc897e081c9f3b7d2a5913441ab4816851a9da52158d05ea84d863
|
|
4
|
+
data.tar.gz: 15d0a731a92ac785fd837ca99be1d6521a728446be45087adbf997f338f6456d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a20d9fcccf65d69d08045d196ca54478e65c689941c6a07b302acea78e3f2218b6b96b3039904e5f710fff54fc013ef951ef98b267c24d3c9cbf961066ad8442
|
|
7
|
+
data.tar.gz: 373aac9ed547db8482549be91af26821fba8ed48b4098fae5049ffd9496de97960c7f3176e6ebdbf46e6230196c90058842efce10803d5e5251d321afe623ca8
|
data/CHANGELOG.md
CHANGED
|
@@ -4,8 +4,30 @@ All notable changes to this project are documented in this file. The format
|
|
|
4
4
|
follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/) and the
|
|
5
5
|
project adheres to [Semantic Versioning](https://semver.org/).
|
|
6
6
|
|
|
7
|
+
## [1.0.4] - 2026-09-27
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- Cache the immutable server key instead of allocating it on every Cluster
|
|
12
|
+
lookup.
|
|
13
|
+
- Encode one-level nested command arguments without creating an intermediate
|
|
14
|
+
flattened array.
|
|
15
|
+
- Parse RESP data with a buffer cursor and compact only when another socket
|
|
16
|
+
read is required, reducing response-parser allocations.
|
|
17
|
+
- Attempt non-blocking socket reads and writes before waiting with `IO.select`,
|
|
18
|
+
while preserving read/write deadlines when the socket would block.
|
|
19
|
+
|
|
7
20
|
## [1.0.3] - 2026-09-27
|
|
8
21
|
|
|
22
|
+
### Added
|
|
23
|
+
|
|
24
|
+
- Deterministic fault-injection and bounded thread/Ractor stress tests in the
|
|
25
|
+
standard CI suite.
|
|
26
|
+
- A dependency-free local throughput benchmark run by the default Rake task.
|
|
27
|
+
- A reproducible real-Redis comparison with `redis-client` across 1/2/4/8
|
|
28
|
+
Ractors, pipelines, isolated pools, Cluster, and forced Sentinel failover,
|
|
29
|
+
including latency percentiles, CPU, RSS, allocations, and errors.
|
|
30
|
+
|
|
9
31
|
### Fixed
|
|
10
32
|
|
|
11
33
|
- Consume complete RESP arrays, maps, sets, pushes, and attributes before
|
|
@@ -91,6 +113,7 @@ project adheres to [Semantic Versioning](https://semver.org/).
|
|
|
91
113
|
TLS, reconnection), `Pool` owned by a single Ractor, pipelines, and
|
|
92
114
|
lifecycle callbacks via `callback-collection`.
|
|
93
115
|
|
|
116
|
+
[1.0.4]: https://github.com/nicolasva/solid-redis/compare/v1.0.3...v1.0.4
|
|
94
117
|
[1.0.3]: https://github.com/nicolasva/solid-redis/compare/v1.0.2...v1.0.3
|
|
95
118
|
[1.0.2]: https://github.com/nicolasva/solid-redis/compare/v1.0.1...v1.0.2
|
|
96
119
|
[1.0.1]: https://github.com/nicolasva/solid-redis/compare/v1.0.0...v1.0.1
|
data/README.md
CHANGED
|
@@ -583,6 +583,108 @@ futures. It cannot transparently replace a block-based synchronous pool
|
|
|
583
583
|
without defining backpressure, cancellation, transaction, Pub/Sub, and
|
|
584
584
|
exception protocols.
|
|
585
585
|
|
|
586
|
+
## Benchmark
|
|
587
|
+
|
|
588
|
+
<!-- benchmark-results:start -->
|
|
589
|
+
This is a local-loopback microbenchmark, not a prediction of application
|
|
590
|
+
performance. It excludes Redis server CPU/RAM and network latency.
|
|
591
|
+
Cluster rows compare `solid-redis` with `redis-cluster-client`, the
|
|
592
|
+
Cluster implementation built on `redis-client`. Unsupported combinations
|
|
593
|
+
are reported rather than replaced with a different concurrency model.
|
|
594
|
+
|
|
595
|
+
**Environment:** Ruby 3.4.4 (arm64-darwin24); solid-redis 1.0.3; Redis server v=8.10.0 sha=00000000:1 malloc=libc bits=64 build=80fd3081013fc32b; redis-client 0.30.1; redis-cluster-client 0.17.1; Apple M2 Max, 12 logical CPUs, 96 GiB RAM, macOS 26.6.2.
|
|
596
|
+
|
|
597
|
+
Each row is measured in a fresh Ruby process. Both clients use RESP2,
|
|
598
|
+
identical commands and the same local Redis topology. Client order is
|
|
599
|
+
alternated between runs; values are medians of 5 runs.
|
|
600
|
+
Regular workloads warm for 2 seconds and measure
|
|
601
|
+
for 10 seconds. Pipeline latency is amortized
|
|
602
|
+
per command (batch size 50). The isolated-pool scenario creates a
|
|
603
|
+
five-connection pool inside each Ractor, warms it with
|
|
604
|
+
1,000 PINGs, then measures 100,000
|
|
605
|
+
PINGs per Ractor.
|
|
606
|
+
CPU is client-process CPU divided by wall time and may exceed 100% with
|
|
607
|
+
multiple Ractors. Peak RSS excludes Redis server processes. Sentinel
|
|
608
|
+
rows kill the master process 0.5 seconds after measurement starts and
|
|
609
|
+
verify that every Ractor resumes on the promoted replica. Recovery is
|
|
610
|
+
measured from the kill to each Ractor's first successful response.
|
|
611
|
+
Throughput counts successful commands; errors are failed commands
|
|
612
|
+
observed during the measured interval. Allocation and RSS measurements
|
|
613
|
+
include the identical latency-recording harness used for both clients, so
|
|
614
|
+
they are comparative rather than intrinsic library-only costs.
|
|
615
|
+
|
|
616
|
+
Reproduce the full run (requires `redis-server` and `redis-cli`):
|
|
617
|
+
|
|
618
|
+
```sh
|
|
619
|
+
BENCHMARK_README=README.md bundle exec rake benchmark:comparison
|
|
620
|
+
```
|
|
621
|
+
|
|
622
|
+
### GET / SET
|
|
623
|
+
|
|
624
|
+
| Ractors | Client | Throughput (ops/s) | p50 (ms) | p95 (ms) | p99 (ms) | CPU | Peak RSS | Allocations/op | Errors/run |
|
|
625
|
+
|---:|---|---:|---:|---:|---:|---:|---:|---:|---:|
|
|
626
|
+
| 1 | `redis-client` | 35,636 | 0.027 | 0.033 | 0.045 | 58.3% | 50.6 MiB | 17.4 | 0 |
|
|
627
|
+
| 1 | `solid-redis` | 33,891 | 0.028 | 0.034 | 0.051 | 52.4% | 49.0 MiB | 28.9 | 0 |
|
|
628
|
+
| 2 | `redis-client` | 53,941 | 0.035 | 0.049 | 0.069 | 114.6% | 58.6 MiB | 17.3 | 0 |
|
|
629
|
+
| 2 | `solid-redis` | 56,594 | 0.033 | 0.045 | 0.090 | 104.7% | 57.9 MiB | 28.7 | 0 |
|
|
630
|
+
| 4 | `redis-client` | 67,608 | 0.055 | 0.092 | 0.131 | 238.3% | 63.7 MiB | 17.3 | 0 |
|
|
631
|
+
| 4 | `solid-redis` | 75,539 | 0.049 | 0.082 | 0.141 | 204.1% | 63.8 MiB | 28.5 | 0 |
|
|
632
|
+
| 8 | `redis-client` | 48,828 | 0.078 | 0.171 | 0.236 | 268.5% | 75.4 MiB | 17.3 | 0 |
|
|
633
|
+
| 8 | `solid-redis` | 80,691 | 0.087 | 0.172 | 0.267 | 431.4% | 69.5 MiB | 28.2 | 0 |
|
|
634
|
+
|
|
635
|
+
### Pipelines
|
|
636
|
+
|
|
637
|
+
| Ractors | Client | Throughput (ops/s) | p50 (ms) | p95 (ms) | p99 (ms) | CPU | Peak RSS | Allocations/op | Errors/run |
|
|
638
|
+
|---:|---|---:|---:|---:|---:|---:|---:|---:|---:|
|
|
639
|
+
| 1 | `redis-client` | 262,482 | 0.004 | 0.005 | 0.007 | 81.5% | 39.5 MiB | 12.6 | 0 |
|
|
640
|
+
| 1 | `solid-redis` | 317,150 | 0.003 | 0.004 | 0.006 | 77.9% | 41.0 MiB | 16.2 | 0 |
|
|
641
|
+
| 2 | `redis-client` | 270,197 | 0.007 | 0.010 | 0.013 | 149.9% | 39.9 MiB | 12.5 | 0 |
|
|
642
|
+
| 2 | `solid-redis` | 459,445 | 0.004 | 0.007 | 0.009 | 147.5% | 42.5 MiB | 15.9 | 0 |
|
|
643
|
+
| 4 | `redis-client` | 222,813 | 0.017 | 0.025 | 0.031 | 282.8% | 40.0 MiB | 12.5 | 0 |
|
|
644
|
+
| 4 | `solid-redis` | 464,640 | 0.008 | 0.014 | 0.017 | 251.9% | 43.2 MiB | 15.6 | 0 |
|
|
645
|
+
| 8 | `redis-client` | 204,898 | 0.004 | 0.055 | 0.063 | 314.2% | 41.9 MiB | 12.5 | 0 |
|
|
646
|
+
| 8 | `solid-redis` | 341,323 | 0.021 | 0.042 | 0.047 | 550.7% | 43.4 MiB | 15.5 | 0 |
|
|
647
|
+
|
|
648
|
+
### Isolated pool per Ractor
|
|
649
|
+
|
|
650
|
+
| Ractors | Client | Throughput (ops/s) | p50 (ms) | p95 (ms) | p99 (ms) | CPU | Peak RSS | Allocations/op | Errors/run |
|
|
651
|
+
|---:|---|---:|---:|---:|---:|---:|---:|---:|---:|
|
|
652
|
+
| 1 | `redis-client` | unsupported: Ractor::IsolationError (`connection_pool` uses non-shareable global state) | — | — | — | — | — | — | — |
|
|
653
|
+
| 1 | `solid-redis` | 34,528 | 0.028 | 0.033 | 0.043 | 53.3% | 39.0 MiB | 25.0 | 0 |
|
|
654
|
+
| 2 | `redis-client` | unsupported: Ractor::IsolationError (`connection_pool` uses non-shareable global state) | — | — | — | — | — | — | — |
|
|
655
|
+
| 2 | `solid-redis` | 57,408 | 0.032 | 0.046 | 0.086 | 106.3% | 44.4 MiB | 24.8 | 0 |
|
|
656
|
+
| 4 | `redis-client` | unsupported: Ractor::IsolationError (`connection_pool` uses non-shareable global state) | — | — | — | — | — | — | — |
|
|
657
|
+
| 4 | `solid-redis` | 78,461 | 0.047 | 0.078 | 0.129 | 205.4% | 54.1 MiB | 24.6 | 0 |
|
|
658
|
+
| 8 | `redis-client` | unsupported: Ractor::IsolationError (`connection_pool` uses non-shareable global state) | — | — | — | — | — | — | — |
|
|
659
|
+
| 8 | `solid-redis` | 72,809 | 0.071 | 0.129 | 0.202 | 297.3% | 68.9 MiB | 24.4 | 0 |
|
|
660
|
+
|
|
661
|
+
### Cluster
|
|
662
|
+
|
|
663
|
+
| Ractors | Client | Throughput (ops/s) | p50 (ms) | p95 (ms) | p99 (ms) | CPU | Peak RSS | Allocations/op | Errors/run |
|
|
664
|
+
|---:|---|---:|---:|---:|---:|---:|---:|---:|---:|
|
|
665
|
+
| 1 | `redis-client` | 29,071 | 0.033 | 0.040 | 0.051 | 64.8% | 48.8 MiB | 19.4 | 0 |
|
|
666
|
+
| 1 | `solid-redis` | 29,213 | 0.033 | 0.038 | 0.056 | 57.1% | 47.6 MiB | 34.9 | 0 |
|
|
667
|
+
| 2 | `redis-client` | 50,333 | 0.037 | 0.051 | 0.078 | 124.7% | 57.8 MiB | 19.3 | 0 |
|
|
668
|
+
| 2 | `solid-redis` | 51,805 | 0.036 | 0.050 | 0.097 | 117.2% | 57.0 MiB | 34.7 | 0 |
|
|
669
|
+
| 4 | `redis-client` | 60,752 | 0.062 | 0.099 | 0.139 | 252.6% | 62.5 MiB | 19.3 | 0 |
|
|
670
|
+
| 4 | `solid-redis` | 66,626 | 0.055 | 0.089 | 0.152 | 225.9% | 61.2 MiB | 34.4 | 0 |
|
|
671
|
+
| 8 | `redis-client` | 43,258 | 0.089 | 0.186 | 0.253 | 278.1% | 75.4 MiB | 19.3 | 0 |
|
|
672
|
+
| 8 | `solid-redis` | 48,644 | 0.079 | 0.154 | 0.248 | 241.4% | 74.7 MiB | 34.3 | 0 |
|
|
673
|
+
|
|
674
|
+
### Sentinel master crash
|
|
675
|
+
|
|
676
|
+
| Ractors | Client | Throughput (ops/s) | p50 (ms) | p95 (ms) | p99 (ms) | Recovery p50 (ms) | Recovery max (ms) | CPU | Peak RSS | Allocations/op | Errors/run |
|
|
677
|
+
|---:|---|---:|---:|---:|---:|---:|---:|---:|---:|---:|---:|
|
|
678
|
+
| 1 | `redis-client` | 29,378 | 0.028 | 0.035 | 0.046 | 1333.8 | 1333.8 | 61.9% | 52.3 MiB | 20.1 | 2050 |
|
|
679
|
+
| 1 | `solid-redis` | 28,794 | 0.029 | 0.035 | 0.050 | 1319.1 | 1319.1 | 55.5% | 48.3 MiB | 33.3 | 2090 |
|
|
680
|
+
| 2 | `redis-client` | 30,829 | 0.036 | 0.049 | 0.070 | 4242.9 | 4243.0 | 87.8% | 53.4 MiB | 20.4 | 3080 |
|
|
681
|
+
| 2 | `solid-redis` | 31,074 | 0.033 | 0.045 | 0.093 | 4440.4 | 4451.4 | 77.3% | 50.3 MiB | 33.1 | 2202 |
|
|
682
|
+
| 4 | `redis-client` | 36,404 | 0.054 | 0.093 | 0.131 | 4302.8 | 4870.8 | 157.2% | 58.0 MiB | 20.5 | 3113 |
|
|
683
|
+
| 4 | `solid-redis` | 41,080 | 0.048 | 0.081 | 0.136 | 4802.3 | 4962.6 | 132.6% | 56.0 MiB | 32.0 | 2251 |
|
|
684
|
+
| 8 | `redis-client` | 48,133 | 0.117 | 0.219 | 0.297 | 2278.4 | 2741.5 | 434.1% | 61.5 MiB | 19.7 | 3114 |
|
|
685
|
+
| 8 | `solid-redis` | 63,627 | 0.087 | 0.171 | 0.277 | 2073.7 | 2085.0 | 374.0% | 64.4 MiB | 30.6 | 2268 |
|
|
686
|
+
<!-- benchmark-results:end -->
|
|
687
|
+
|
|
586
688
|
## Development
|
|
587
689
|
|
|
588
690
|
```sh
|
|
@@ -590,8 +692,15 @@ bundle install
|
|
|
590
692
|
bundle exec rake
|
|
591
693
|
```
|
|
592
694
|
|
|
593
|
-
The default task runs the Minitest suite
|
|
594
|
-
CI runs
|
|
695
|
+
The default task runs the Minitest suite, a deterministic local throughput
|
|
696
|
+
benchmark, and builds the gem in `pkg/`. CI runs all three on Ruby 3.1 through
|
|
697
|
+
4.0. The test suite includes bounded thread/Ractor stress and fault injection
|
|
698
|
+
for truncated responses, timeouts, reconnects, Sentinel, and Cluster errors.
|
|
699
|
+
Run only the benchmark with:
|
|
700
|
+
|
|
701
|
+
```sh
|
|
702
|
+
bundle exec rake benchmark
|
|
703
|
+
```
|
|
595
704
|
|
|
596
705
|
The suite needs no running Redis: it uses an in-process fake server
|
|
597
706
|
(`test/support/fake_redis_server.rb`) that speaks RESP2/RESP3, Sentinel,
|
data/lib/solid_redis/client.rb
CHANGED
|
@@ -202,14 +202,19 @@ module SolidRedis
|
|
|
202
202
|
|
|
203
203
|
def write(payload)
|
|
204
204
|
offset = 0
|
|
205
|
+
deadline = nil
|
|
205
206
|
while offset < payload.bytesize
|
|
206
|
-
|
|
207
|
-
|
|
207
|
+
chunk = offset.zero? ? payload : payload.byteslice(offset..)
|
|
208
|
+
written = @socket.write_nonblock(chunk, exception: false)
|
|
209
|
+
if written == :wait_writable
|
|
210
|
+
deadline ||= monotonic_time + @target.write_timeout
|
|
211
|
+
remaining = deadline - monotonic_time
|
|
212
|
+
if remaining <= 0 || !IO.select(nil, [@socket], nil, remaining)
|
|
213
|
+
raise TimeoutError, "Redis write timed out after #{@target.write_timeout}s"
|
|
214
|
+
end
|
|
215
|
+
next
|
|
208
216
|
end
|
|
209
217
|
|
|
210
|
-
written = @socket.write_nonblock(payload.byteslice(offset..), exception: false)
|
|
211
|
-
next if written == :wait_writable
|
|
212
|
-
|
|
213
218
|
offset += written
|
|
214
219
|
end
|
|
215
220
|
rescue IOError, SystemCallError => error
|
data/lib/solid_redis/config.rb
CHANGED
|
@@ -56,6 +56,7 @@ module SolidRedis
|
|
|
56
56
|
@ssl = !!ssl
|
|
57
57
|
@ssl_params = Shareable.copy(ssl_params, label: "ssl_params") if ssl_params
|
|
58
58
|
@callbacks = Shareable.copy(callbacks, label: "callbacks") if callbacks
|
|
59
|
+
@server_key = [@path, @host, @port].freeze
|
|
59
60
|
Ractor.make_shareable(self)
|
|
60
61
|
end
|
|
61
62
|
|
|
@@ -72,7 +73,7 @@ module SolidRedis
|
|
|
72
73
|
end
|
|
73
74
|
|
|
74
75
|
def server_key
|
|
75
|
-
|
|
76
|
+
@server_key
|
|
76
77
|
end
|
|
77
78
|
|
|
78
79
|
def server_url
|
data/lib/solid_redis/resp.rb
CHANGED
|
@@ -7,15 +7,23 @@ module SolidRedis
|
|
|
7
7
|
module_function
|
|
8
8
|
|
|
9
9
|
def encode(command)
|
|
10
|
-
|
|
11
|
-
raise ArgumentError, "Redis command cannot be empty" if
|
|
10
|
+
length = command.sum { |argument| argument.is_a?(Array) ? argument.length : 1 }
|
|
11
|
+
raise ArgumentError, "Redis command cannot be empty" if length.zero?
|
|
12
12
|
|
|
13
|
-
command.each_with_object(+"*#{
|
|
14
|
-
|
|
15
|
-
|
|
13
|
+
command.each_with_object(+"*#{length}#{CRLF}") do |argument, buffer|
|
|
14
|
+
if argument.is_a?(Array)
|
|
15
|
+
argument.each { |value| append_argument(buffer, value) }
|
|
16
|
+
else
|
|
17
|
+
append_argument(buffer, argument)
|
|
18
|
+
end
|
|
16
19
|
end
|
|
17
20
|
end
|
|
18
21
|
|
|
22
|
+
def append_argument(buffer, argument)
|
|
23
|
+
value = encode_argument(argument)
|
|
24
|
+
buffer << "$#{value.bytesize}#{CRLF}#{value}#{CRLF}"
|
|
25
|
+
end
|
|
26
|
+
|
|
19
27
|
def encode_argument(value)
|
|
20
28
|
case value
|
|
21
29
|
when String then value
|
|
@@ -32,6 +40,7 @@ module SolidRedis
|
|
|
32
40
|
@io = io
|
|
33
41
|
@read_timeout = read_timeout
|
|
34
42
|
@buffer = +""
|
|
43
|
+
@offset = 0
|
|
35
44
|
end
|
|
36
45
|
|
|
37
46
|
# Temporarily overrides the read timeout. +nil+ waits forever, which is
|
|
@@ -49,7 +58,7 @@ module SolidRedis
|
|
|
49
58
|
# leaves a partially consumed frame behind, so it is the safe way to
|
|
50
59
|
# poll for the next Pub/Sub message.
|
|
51
60
|
def wait_readable(timeout)
|
|
52
|
-
return true
|
|
61
|
+
return true if available_bytes.positive?
|
|
53
62
|
return true unless @io.respond_to?(:to_io)
|
|
54
63
|
|
|
55
64
|
!IO.select([@io], nil, nil, timeout).nil?
|
|
@@ -155,28 +164,30 @@ module SolidRedis
|
|
|
155
164
|
|
|
156
165
|
def read_line
|
|
157
166
|
loop do
|
|
158
|
-
if (index = @buffer.index(CRLF))
|
|
159
|
-
|
|
167
|
+
if (index = @buffer.index(CRLF, @offset))
|
|
168
|
+
value = @buffer.byteslice(@offset, index - @offset)
|
|
169
|
+
@offset = index + 2
|
|
170
|
+
clear_consumed_buffer
|
|
171
|
+
return value
|
|
160
172
|
end
|
|
161
173
|
fill_buffer
|
|
162
174
|
end
|
|
163
175
|
end
|
|
164
176
|
|
|
165
177
|
def read_bytes(length)
|
|
166
|
-
fill_buffer while
|
|
167
|
-
@buffer.
|
|
178
|
+
fill_buffer while available_bytes < length
|
|
179
|
+
value = @buffer.byteslice(@offset, length)
|
|
180
|
+
@offset += length
|
|
181
|
+
clear_consumed_buffer
|
|
182
|
+
value
|
|
168
183
|
end
|
|
169
184
|
|
|
170
185
|
def fill_buffer
|
|
186
|
+
compact_buffer
|
|
171
187
|
wait_for = :readable
|
|
188
|
+
deadline = nil
|
|
172
189
|
loop do
|
|
173
190
|
if @io.respond_to?(:to_io)
|
|
174
|
-
readers = wait_for == :readable ? [@io] : nil
|
|
175
|
-
writers = wait_for == :writable ? [@io] : nil
|
|
176
|
-
unless IO.select(readers, writers, nil, @read_timeout)
|
|
177
|
-
raise TimeoutError, "Redis read timed out after #{@read_timeout}s"
|
|
178
|
-
end
|
|
179
|
-
|
|
180
191
|
chunk = @io.read_nonblock(16_384, exception: false)
|
|
181
192
|
else
|
|
182
193
|
chunk = @io.read(16_384)
|
|
@@ -184,6 +195,17 @@ module SolidRedis
|
|
|
184
195
|
|
|
185
196
|
if chunk == :wait_readable || chunk == :wait_writable
|
|
186
197
|
wait_for = chunk == :wait_readable ? :readable : :writable
|
|
198
|
+
deadline ||= monotonic_time + @read_timeout if @read_timeout
|
|
199
|
+
remaining = deadline && deadline - monotonic_time
|
|
200
|
+
if remaining && remaining <= 0
|
|
201
|
+
raise TimeoutError, "Redis read timed out after #{@read_timeout}s"
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
readers = wait_for == :readable ? [@io] : nil
|
|
205
|
+
writers = wait_for == :writable ? [@io] : nil
|
|
206
|
+
unless IO.select(readers, writers, nil, remaining)
|
|
207
|
+
raise TimeoutError, "Redis read timed out after #{@read_timeout}s"
|
|
208
|
+
end
|
|
187
209
|
next
|
|
188
210
|
end
|
|
189
211
|
raise EOFError if chunk.nil?
|
|
@@ -195,6 +217,28 @@ module SolidRedis
|
|
|
195
217
|
raise ConnectionError, error.message, cause: error
|
|
196
218
|
end
|
|
197
219
|
|
|
220
|
+
def available_bytes
|
|
221
|
+
@buffer.bytesize - @offset
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def clear_consumed_buffer
|
|
225
|
+
return unless @offset == @buffer.bytesize
|
|
226
|
+
|
|
227
|
+
@buffer.clear
|
|
228
|
+
@offset = 0
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def compact_buffer
|
|
232
|
+
return if @offset.zero?
|
|
233
|
+
|
|
234
|
+
@buffer = @buffer.byteslice(@offset..) || +""
|
|
235
|
+
@offset = 0
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def monotonic_time
|
|
239
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
|
240
|
+
end
|
|
241
|
+
|
|
198
242
|
def error_response(message, exception)
|
|
199
243
|
error = if message.start_with?("NOAUTH", "WRONGPASS")
|
|
200
244
|
AuthenticationError.new(message)
|
data/lib/solid_redis/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: solid-redis
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.4
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Nicolas Vandenbogaerde
|
|
@@ -71,6 +71,34 @@ dependencies:
|
|
|
71
71
|
- - "~>"
|
|
72
72
|
- !ruby/object:Gem::Version
|
|
73
73
|
version: '13.0'
|
|
74
|
+
- !ruby/object:Gem::Dependency
|
|
75
|
+
name: redis-client
|
|
76
|
+
requirement: !ruby/object:Gem::Requirement
|
|
77
|
+
requirements:
|
|
78
|
+
- - "~>"
|
|
79
|
+
- !ruby/object:Gem::Version
|
|
80
|
+
version: 0.30.1
|
|
81
|
+
type: :development
|
|
82
|
+
prerelease: false
|
|
83
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
84
|
+
requirements:
|
|
85
|
+
- - "~>"
|
|
86
|
+
- !ruby/object:Gem::Version
|
|
87
|
+
version: 0.30.1
|
|
88
|
+
- !ruby/object:Gem::Dependency
|
|
89
|
+
name: redis-cluster-client
|
|
90
|
+
requirement: !ruby/object:Gem::Requirement
|
|
91
|
+
requirements:
|
|
92
|
+
- - "~>"
|
|
93
|
+
- !ruby/object:Gem::Version
|
|
94
|
+
version: '0.17'
|
|
95
|
+
type: :development
|
|
96
|
+
prerelease: false
|
|
97
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
98
|
+
requirements:
|
|
99
|
+
- - "~>"
|
|
100
|
+
- !ruby/object:Gem::Version
|
|
101
|
+
version: '0.17'
|
|
74
102
|
description: Immutable, shareable Redis, Sentinel and Cluster configuration with isolated
|
|
75
103
|
runtime state, pools, and sockets per Ractor. Supports pipelines, blocking commands,
|
|
76
104
|
and Pub/Sub.
|
|
@@ -104,7 +132,7 @@ licenses:
|
|
|
104
132
|
- MIT
|
|
105
133
|
metadata:
|
|
106
134
|
rubygems_mfa_required: 'true'
|
|
107
|
-
documentation_uri: https://www.rubydoc.info/gems/solid-redis/1.0.
|
|
135
|
+
documentation_uri: https://www.rubydoc.info/gems/solid-redis/1.0.4
|
|
108
136
|
source_code_uri: https://github.com/nicolasva/solid-redis
|
|
109
137
|
changelog_uri: https://github.com/nicolasva/solid-redis/blob/main/CHANGELOG.md
|
|
110
138
|
rdoc_options: []
|