tally 1.0.1 → 2.0.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/README.md +23 -2
- data/lib/tally/daily.rb +14 -22
- data/lib/tally/increment.rb +5 -5
- data/lib/tally/key_finder.rb +17 -7
- data/lib/tally/sweeper.rb +3 -3
- data/lib/tally/version.rb +1 -1
- data/lib/tally.rb +18 -2
- metadata +24 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2326dfbbdcb9474f788b14370829771c27cf8945d9a2c4c07208ef78a157bcfa
|
4
|
+
data.tar.gz: 852b21044a153ba21c0eb3f48f282a3157a55f4e535fed2006ea80652263f7b2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 16d1b206ded32742d3fc04973bb52fc066ba2618ee70a692e3b73322b0950957b34534bd9b3e6c5bfc555de5149ca9f61455265ed91d254962077ba0c689a20f
|
7
|
+
data.tar.gz: 5610ac5ba2038971c7aa9e3fb6694971a7cea354939c0a6c65e94515ca6757cc22f4e00a3c095671bf39321d40f6fd9471906a714077e44695be308eb9ac557c
|
data/README.md
CHANGED
@@ -12,8 +12,8 @@ _[Read more about Tally in my blog post introducing it ...](https://johntornow.c
|
|
12
12
|
|
13
13
|
## Requirements
|
14
14
|
|
15
|
-
* Ruby
|
16
|
-
* Rails
|
15
|
+
* Ruby 3.0.3+
|
16
|
+
* Rails 6.1+
|
17
17
|
* Redis 4+
|
18
18
|
|
19
19
|
## Installation
|
@@ -204,10 +204,31 @@ The endpoints can be used to display JSON-formatted data from `Tally::Record`. T
|
|
204
204
|
|
205
205
|
Tally works _really_ well with [Sidekiq](https://github.com/mperham/sidekiq/), but it isn't required. If Sidekiq is installed in your app, Tally will use its connection pooling for Redis connections. If Sidekiq isn't in use, the `Redis.current` connection is used to store stats. If you'd like to override the specific connection used for Tally's redis store, you can do so by setting `Tally.redis_connection` to another instance of `Redis`. This can be useful to use an alternate Redis store for just stats, for example.
|
206
206
|
|
207
|
+
As of version 2.0.0 this connection is automatically used within a [ConnectionPool](https://github.com/mperham/connection_pool).
|
208
|
+
|
207
209
|
```ruby
|
208
210
|
# use an alternate Redis connection (for non-sidekiq integrations)
|
209
211
|
Tally.redis_connection = Redis.new(...)
|
210
212
|
```
|
213
|
+
|
214
|
+
Alternatively, you can just set the config for Redis and `Redis.new` will be called for you:
|
215
|
+
|
216
|
+
```ruby
|
217
|
+
# provide Redis config
|
218
|
+
Tally.config.redis_config = {
|
219
|
+
driver: :ruby,
|
220
|
+
url: "redis://127.0.0.1:6379/10",
|
221
|
+
ssl_params: {
|
222
|
+
verify_mode: OpenSSL::SSL::VERIFY_NONE
|
223
|
+
}
|
224
|
+
}
|
225
|
+
|
226
|
+
# then Tally uses the connection within a pool:
|
227
|
+
Tally.redis do |connection|
|
228
|
+
connection.incr("test")
|
229
|
+
end
|
230
|
+
```
|
231
|
+
|
211
232
|
## Issues
|
212
233
|
|
213
234
|
If you have any issues or find bugs running Tally, please [report them on Github](https://github.com/jdtornow/tally/issues).
|
data/lib/tally/daily.rb
CHANGED
@@ -10,26 +10,6 @@ module Tally
|
|
10
10
|
|
11
11
|
private
|
12
12
|
|
13
|
-
def all_keys
|
14
|
-
@keys ||= build_keys_from_redis
|
15
|
-
end
|
16
|
-
|
17
|
-
def build_keys_from_redis
|
18
|
-
result = []
|
19
|
-
cursor = ""
|
20
|
-
|
21
|
-
scan = scan_from_redis
|
22
|
-
|
23
|
-
while cursor != "0"
|
24
|
-
result << scan.last
|
25
|
-
cursor = scan.first
|
26
|
-
|
27
|
-
scan = scan_from_redis(cursor: cursor)
|
28
|
-
end
|
29
|
-
|
30
|
-
result.flatten
|
31
|
-
end
|
32
|
-
|
33
13
|
def day_key
|
34
14
|
@day_key ||= day.strftime(Tally.config.date_format)
|
35
15
|
end
|
@@ -39,8 +19,20 @@ module Tally
|
|
39
19
|
end
|
40
20
|
|
41
21
|
def scan_from_redis(cursor: "0")
|
42
|
-
Tally.redis
|
43
|
-
|
22
|
+
klass = Tally.redis { |conn| conn.class.to_s }
|
23
|
+
|
24
|
+
# if we're using sidekiq / RedisClient, scan needs a block, and doesn't worry about the cursor
|
25
|
+
if klass == "Sidekiq::RedisClientAdapter::CompatClient"
|
26
|
+
Tally.redis do |conn|
|
27
|
+
[
|
28
|
+
"0", # fake cursor to match redis-rb output
|
29
|
+
conn.sscan(daily_key, "MATCH", scan_key, "COUNT", 25).to_a
|
30
|
+
]
|
31
|
+
end
|
32
|
+
else
|
33
|
+
Tally.redis do |conn|
|
34
|
+
conn.sscan(daily_key, cursor, match: scan_key, count: 25)
|
35
|
+
end
|
44
36
|
end
|
45
37
|
end
|
46
38
|
|
data/lib/tally/increment.rb
CHANGED
@@ -5,12 +5,12 @@ module Tally
|
|
5
5
|
|
6
6
|
def increment(by = 1)
|
7
7
|
Tally.redis do |conn|
|
8
|
-
conn.multi do
|
9
|
-
|
10
|
-
|
8
|
+
conn.multi do |pipeline|
|
9
|
+
pipeline.incrby(redis_key, by)
|
10
|
+
pipeline.expire(redis_key, Tally.config.ttl.to_i) if Tally.config.ttl.present?
|
11
11
|
|
12
|
-
|
13
|
-
|
12
|
+
pipeline.sadd(daily_key, simple_key)
|
13
|
+
pipeline.expire(daily_key, Tally.config.ttl.to_i) if Tally.config.ttl.present?
|
14
14
|
end
|
15
15
|
end
|
16
16
|
end
|
data/lib/tally/key_finder.rb
CHANGED
@@ -73,18 +73,16 @@ module Tally
|
|
73
73
|
|
74
74
|
def build_keys_from_redis
|
75
75
|
result = []
|
76
|
-
cursor =
|
77
|
-
|
78
|
-
scan = scan_from_redis
|
76
|
+
cursor = nil
|
79
77
|
|
80
78
|
while cursor != "0"
|
79
|
+
scan = scan_from_redis(cursor: cursor.presence || "0")
|
80
|
+
|
81
81
|
result << scan.last
|
82
82
|
cursor = scan.first
|
83
|
-
|
84
|
-
scan = scan_from_redis(cursor: cursor)
|
85
83
|
end
|
86
84
|
|
87
|
-
result.flatten
|
85
|
+
result.flatten.uniq
|
88
86
|
end
|
89
87
|
|
90
88
|
def day_key
|
@@ -100,7 +98,19 @@ module Tally
|
|
100
98
|
end
|
101
99
|
|
102
100
|
def scan_from_redis(cursor: "0")
|
103
|
-
Tally.redis { |conn| conn.
|
101
|
+
klass = Tally.redis { |conn| conn.class.to_s }
|
102
|
+
|
103
|
+
# if we're using sidekiq / RedisClient, scan needs a block, and doesn't worry about the cursor
|
104
|
+
if klass == "Sidekiq::RedisClientAdapter::CompatClient"
|
105
|
+
Tally.redis do |conn|
|
106
|
+
[
|
107
|
+
"0", # fake cursor to match redis-rb output
|
108
|
+
conn.scan("MATCH", scan_key).to_a
|
109
|
+
]
|
110
|
+
end
|
111
|
+
else
|
112
|
+
Tally.redis { |conn| conn.scan(cursor, match: scan_key) }
|
113
|
+
end
|
104
114
|
end
|
105
115
|
|
106
116
|
def scan_key
|
data/lib/tally/sweeper.rb
CHANGED
@@ -22,10 +22,10 @@ module Tally
|
|
22
22
|
|
23
23
|
def sweep!
|
24
24
|
Tally.redis do |conn|
|
25
|
-
purgeable_keys.in_groups_of(25, fill_with =
|
26
|
-
conn.pipelined do
|
25
|
+
purgeable_keys.in_groups_of(25, fill_with = false).each do |group|
|
26
|
+
conn.pipelined do |pipeline|
|
27
27
|
group.each do |key|
|
28
|
-
|
28
|
+
pipeline.del(key)
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
data/lib/tally/version.rb
CHANGED
data/lib/tally.rb
CHANGED
@@ -46,6 +46,12 @@ module Tally
|
|
46
46
|
# Archivers get queued into the background with ActiveJob by default
|
47
47
|
# Set to :now to run inline
|
48
48
|
config.perform_calculators = :later
|
49
|
+
|
50
|
+
# override to set default redis configuration for Tally when Sidekiq is not present
|
51
|
+
config.redis_config = {}
|
52
|
+
|
53
|
+
# override to set connection pool details for Redis
|
54
|
+
config.redis_pool_config = {}
|
49
55
|
end
|
50
56
|
|
51
57
|
# If sidekiq is available, piggyback on its pooling
|
@@ -57,18 +63,28 @@ module Tally
|
|
57
63
|
if defined?(Sidekiq)
|
58
64
|
Sidekiq.redis(&block)
|
59
65
|
else
|
60
|
-
|
66
|
+
redis_pool.with(&block)
|
61
67
|
end
|
62
68
|
end
|
63
69
|
|
64
70
|
def self.redis_connection
|
65
|
-
@redis_connection ||= Redis.
|
71
|
+
@redis_connection ||= Redis.new(Tally.config.redis_config)
|
66
72
|
end
|
67
73
|
|
68
74
|
def self.redis_connection=(connection)
|
69
75
|
@redis_connection = connection
|
70
76
|
end
|
71
77
|
|
78
|
+
def self.redis_pool
|
79
|
+
@redis_pool ||= ConnectionPool.new(Tally.config.redis_pool_config) do
|
80
|
+
redis_connection
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def self.redis_pool=(pool)
|
85
|
+
@redis_pool = pool
|
86
|
+
end
|
87
|
+
|
72
88
|
def self.increment(*args)
|
73
89
|
Increment.public_send(:increment, *args)
|
74
90
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tally
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- John D. Tornow
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-12-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -19,7 +19,7 @@ dependencies:
|
|
19
19
|
version: 5.2.0
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: '
|
22
|
+
version: '8'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -29,7 +29,7 @@ dependencies:
|
|
29
29
|
version: 5.2.0
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: '
|
32
|
+
version: '8'
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: redis
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -44,6 +44,20 @@ dependencies:
|
|
44
44
|
- - ">="
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: '4.1'
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: connection_pool
|
49
|
+
requirement: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '2.0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
requirements:
|
58
|
+
- - ">="
|
59
|
+
- !ruby/object:Gem::Version
|
60
|
+
version: '2.0'
|
47
61
|
- !ruby/object:Gem::Dependency
|
48
62
|
name: kaminari-activerecord
|
49
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -78,14 +92,14 @@ dependencies:
|
|
78
92
|
requirements:
|
79
93
|
- - "~>"
|
80
94
|
- !ruby/object:Gem::Version
|
81
|
-
version: '
|
95
|
+
version: '6'
|
82
96
|
type: :development
|
83
97
|
prerelease: false
|
84
98
|
version_requirements: !ruby/object:Gem::Requirement
|
85
99
|
requirements:
|
86
100
|
- - "~>"
|
87
101
|
- !ruby/object:Gem::Version
|
88
|
-
version: '
|
102
|
+
version: '6'
|
89
103
|
- !ruby/object:Gem::Dependency
|
90
104
|
name: factory_bot_rails
|
91
105
|
requirement: !ruby/object:Gem::Requirement
|
@@ -106,28 +120,14 @@ dependencies:
|
|
106
120
|
requirements:
|
107
121
|
- - "~>"
|
108
122
|
- !ruby/object:Gem::Version
|
109
|
-
version: '
|
110
|
-
type: :development
|
111
|
-
prerelease: false
|
112
|
-
version_requirements: !ruby/object:Gem::Requirement
|
113
|
-
requirements:
|
114
|
-
- - "~>"
|
115
|
-
- !ruby/object:Gem::Version
|
116
|
-
version: '4.2'
|
117
|
-
- !ruby/object:Gem::Dependency
|
118
|
-
name: simplecov
|
119
|
-
requirement: !ruby/object:Gem::Requirement
|
120
|
-
requirements:
|
121
|
-
- - "~>"
|
122
|
-
- !ruby/object:Gem::Version
|
123
|
-
version: '0.11'
|
123
|
+
version: '5.1'
|
124
124
|
type: :development
|
125
125
|
prerelease: false
|
126
126
|
version_requirements: !ruby/object:Gem::Requirement
|
127
127
|
requirements:
|
128
128
|
- - "~>"
|
129
129
|
- !ruby/object:Gem::Version
|
130
|
-
version: '
|
130
|
+
version: '5.1'
|
131
131
|
- !ruby/object:Gem::Dependency
|
132
132
|
name: rspec_junit_formatter
|
133
133
|
requirement: !ruby/object:Gem::Requirement
|
@@ -230,14 +230,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
230
230
|
requirements:
|
231
231
|
- - ">="
|
232
232
|
- !ruby/object:Gem::Version
|
233
|
-
version:
|
233
|
+
version: 3.0.3
|
234
234
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
235
235
|
requirements:
|
236
236
|
- - ">="
|
237
237
|
- !ruby/object:Gem::Version
|
238
238
|
version: 1.8.11
|
239
239
|
requirements: []
|
240
|
-
rubygems_version: 3.
|
240
|
+
rubygems_version: 3.3.26
|
241
241
|
signing_key:
|
242
242
|
specification_version: 4
|
243
243
|
summary: Stats collection and reporting
|