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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bfd6d7b4cdc084ad0d1f638ecbf06fe82909c8e437498abcc8d5987b03628f2f
4
- data.tar.gz: e30633b53c9ae6f9db7b324fb12d9da01a4416399c3c399c4a971a616e1429b6
3
+ metadata.gz: 2326dfbbdcb9474f788b14370829771c27cf8945d9a2c4c07208ef78a157bcfa
4
+ data.tar.gz: 852b21044a153ba21c0eb3f48f282a3157a55f4e535fed2006ea80652263f7b2
5
5
  SHA512:
6
- metadata.gz: f3774064bceec83d7b25ade9e3a68799b0676230392241335231ce8318c33bec2b311694f186f1322ea70cef586bf53c3aacef69ffcc02156d125841d015c6d1
7
- data.tar.gz: 9ee909f93c6e0c6430d6b0ffc21c865b7b94a44e7bdd40ab41c6b0ad5c39eef4109c2b52e313015b1cd78c369dc107a05543732746c0313b7e84007b90f7c269
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 2.2+
16
- * Rails 5.2.x+
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 do |conn|
43
- conn.sscan(daily_key, cursor, match: scan_key, count: 25)
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
 
@@ -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
- conn.incrby(redis_key, by)
10
- conn.expire(redis_key, Tally.config.ttl) if Tally.config.ttl.present?
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
- conn.sadd(daily_key, simple_key)
13
- conn.expire(daily_key, Tally.config.ttl) if Tally.config.ttl.present?
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
@@ -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.scan(cursor, match: scan_key) }
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 = nil).each do |group|
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
- conn.del(key)
28
+ pipeline.del(key)
29
29
  end
30
30
  end
31
31
  end
data/lib/tally/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  module Tally
2
2
 
3
- VERSION = "1.0.1"
3
+ VERSION = "2.0.0"
4
4
 
5
5
  end
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
- block.call(redis_connection)
66
+ redis_pool.with(&block)
61
67
  end
62
68
  end
63
69
 
64
70
  def self.redis_connection
65
- @redis_connection ||= Redis.current
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: 1.0.1
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-01-21 00:00:00.000000000 Z
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: '7'
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: '7'
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: '4.0'
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: '4.0'
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: '4.2'
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: '0.11'
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: 2.5.7
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.2.32
240
+ rubygems_version: 3.3.26
241
241
  signing_key:
242
242
  specification_version: 4
243
243
  summary: Stats collection and reporting