redis-time-series 0.2.0 → 0.5.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/rspec.yml +15 -0
- data/CHANGELOG.md +23 -0
- data/Gemfile.lock +10 -2
- data/README.md +164 -25
- data/bin/console +3 -9
- data/bin/setup +29 -6
- data/lib/ext/time_msec.rb +29 -0
- data/lib/redis-time-series.rb +8 -5
- data/lib/redis/time_series.rb +255 -65
- data/lib/redis/time_series/aggregation.rb +88 -0
- data/lib/redis/time_series/client.rb +77 -0
- data/lib/redis/time_series/errors.rb +19 -0
- data/lib/redis/time_series/filters.rb +169 -0
- data/lib/redis/time_series/info.rb +65 -10
- data/lib/redis/time_series/rule.rb +49 -0
- data/lib/redis/time_series/sample.rb +22 -6
- data/lib/redis/time_series/version.rb +6 -0
- data/redis-time-series.gemspec +4 -3
- metadata +24 -4
- data/lib/time/msec.rb +0 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 461a6f3842867d1ba51440e7576aad3e9b92ecd02700cd59e5508c0e8bbfcaa7
|
4
|
+
data.tar.gz: 0c03af91af0eaaa37917db2cad21417c38709a53b223ed2864bad0f9857fa1f7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 56dcd4439b2f4f06469237d2925d84b2ffabc40e2dccb608d5489b78f0e2a5b299881487b55e67fb48f1c9d0f7f56951ee98254ae84229b1827fb4cf3683ca44
|
7
|
+
data.tar.gz: 860e638f906b9dc19358e6156ad6a0488452be0be499853926742073cf6e85d00f4e95755f1659feae9763334eebbab044147fa3d94512dbb2a91360ec08728b
|
data/.github/workflows/rspec.yml
CHANGED
@@ -16,13 +16,28 @@ jobs:
|
|
16
16
|
image: redislabs/redistimeseries:latest
|
17
17
|
ports:
|
18
18
|
- 6379:6379/tcp
|
19
|
+
env:
|
20
|
+
CC_TEST_REPORTER_ID: ${{ secrets.CC_TEST_REPORTER_ID }}
|
21
|
+
GIT_COMMIT_SHA: ${{ github.sha }}
|
22
|
+
GIT_BRANCH: ${{ github.head_ref }}
|
19
23
|
steps:
|
20
24
|
- uses: actions/checkout@v2
|
21
25
|
- name: Set up Ruby
|
22
26
|
uses: ruby/setup-ruby@v1
|
23
27
|
with:
|
24
28
|
ruby-version: 2.6
|
29
|
+
- name: Set up CodeClimate
|
30
|
+
run: |
|
31
|
+
curl -L https://codeclimate.com/downloads/test-reporter/test-reporter-latest-linux-amd64 > ./cc-test-reporter
|
32
|
+
chmod +x ./cc-test-reporter
|
33
|
+
./cc-test-reporter before-build
|
25
34
|
- name: Install dependencies
|
26
35
|
run: bundle install
|
27
36
|
- name: Run specs
|
28
37
|
run: bundle exec rake spec
|
38
|
+
- name: Upload coverage report
|
39
|
+
run: ./cc-test-reporter after-build -t simplecov coverage/.resultset.json
|
40
|
+
- uses: actions/upload-artifact@v2
|
41
|
+
with:
|
42
|
+
name: coverage
|
43
|
+
path: coverage/
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,29 @@
|
|
2
2
|
|
3
3
|
## Unreleased
|
4
4
|
|
5
|
+
## 0.5.2
|
6
|
+
* Add chunk_type to info struct (#47)
|
7
|
+
|
8
|
+
## 0.5.1
|
9
|
+
* Update Info struct for RTS 1.4 compatibility (#45)
|
10
|
+
|
11
|
+
## 0.5.0
|
12
|
+
* Fix aggregations for TS.RANGE command (#34)
|
13
|
+
* Extract client handling into Client module (#32)
|
14
|
+
* Add `uncompressed` param to TS.ADD, TS.INCRBY, TS.DECRBY (#35)
|
15
|
+
* Add `Redis::TimeSeries::Rule` object (#38)
|
16
|
+
* Add [YARD documentation](https://rubydoc.info/gems/redis-time-series) (#40)
|
17
|
+
|
18
|
+
## 0.4.0
|
19
|
+
* Added [hash-based filter DSL](https://github.com/dzunk/redis-time-series/tree/7173c73588da50614c02f9c89bf2ecef77766a78#filter-dsl)
|
20
|
+
* Removed `Time#ts_msec` monkey-patch
|
21
|
+
* Renamed `TimeSeries.queryindex` to `.query_index`
|
22
|
+
* Added `TS.CREATERULE` and `TS.DELETERULE` commands
|
23
|
+
* Renamed `InvalidFilters` to `FilterError`
|
24
|
+
|
25
|
+
## 0.3.0
|
26
|
+
* Added `TS.QUERYINDEX` command
|
27
|
+
|
5
28
|
## 0.2.0
|
6
29
|
* Converted `#info` to a struct instead of a hash.
|
7
30
|
* Added methods on time series for getting info attributes.
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
redis-time-series (0.
|
4
|
+
redis-time-series (0.5.2)
|
5
5
|
redis (~> 4.0)
|
6
6
|
|
7
7
|
GEM
|
@@ -16,15 +16,17 @@ GEM
|
|
16
16
|
coderay (1.1.3)
|
17
17
|
concurrent-ruby (1.1.6)
|
18
18
|
diff-lcs (1.3)
|
19
|
+
docile (1.3.2)
|
19
20
|
i18n (1.8.3)
|
20
21
|
concurrent-ruby (~> 1.0)
|
22
|
+
json (2.3.1)
|
21
23
|
method_source (1.0.0)
|
22
24
|
minitest (5.14.1)
|
23
25
|
pry (0.13.1)
|
24
26
|
coderay (~> 1.1)
|
25
27
|
method_source (~> 1.0)
|
26
28
|
rake (13.0.1)
|
27
|
-
redis (4.2.
|
29
|
+
redis (4.2.2)
|
28
30
|
rspec (3.9.0)
|
29
31
|
rspec-core (~> 3.9.0)
|
30
32
|
rspec-expectations (~> 3.9.0)
|
@@ -38,6 +40,11 @@ GEM
|
|
38
40
|
diff-lcs (>= 1.2.0, < 2.0)
|
39
41
|
rspec-support (~> 3.9.0)
|
40
42
|
rspec-support (3.9.3)
|
43
|
+
simplecov (0.17.1)
|
44
|
+
docile (~> 1.1)
|
45
|
+
json (>= 1.8, < 3)
|
46
|
+
simplecov-html (~> 0.10.0)
|
47
|
+
simplecov-html (0.10.2)
|
41
48
|
thread_safe (0.3.6)
|
42
49
|
tzinfo (1.2.7)
|
43
50
|
thread_safe (~> 0.1)
|
@@ -53,6 +60,7 @@ DEPENDENCIES
|
|
53
60
|
rake (~> 13.0)
|
54
61
|
redis-time-series!
|
55
62
|
rspec (~> 3.0)
|
63
|
+
simplecov (< 0.18)
|
56
64
|
|
57
65
|
BUNDLED WITH
|
58
66
|
1.17.2
|
data/README.md
CHANGED
@@ -1,4 +1,8 @@
|
|
1
|
-
![](https://github.com/dzunk/redis-time-series/workflows/RSpec/badge.svg)
|
1
|
+
[![RSpec](https://github.com/dzunk/redis-time-series/workflows/RSpec/badge.svg)](https://github.com/dzunk/redis-time-series/actions?query=workflow%3ARSpec+branch%3Amaster)
|
2
|
+
[![Gem Version](https://badge.fury.io/rb/redis-time-series.svg)](https://badge.fury.io/rb/redis-time-series)
|
3
|
+
[![Documentation](https://img.shields.io/badge/docs-rubydoc.info-brightgreen)](https://rubydoc.info/gems/redis-time-series)
|
4
|
+
[![Maintainability](https://api.codeclimate.com/v1/badges/19a5925c20318508b4a4/maintainability)](https://codeclimate.com/github/dzunk/redis-time-series/maintainability)
|
5
|
+
[![Test Coverage](https://api.codeclimate.com/v1/badges/19a5925c20318508b4a4/test_coverage)](https://codeclimate.com/github/dzunk/redis-time-series/test_coverage)
|
2
6
|
|
3
7
|
# RedisTimeSeries
|
4
8
|
|
@@ -72,6 +76,10 @@ Add a single value with a timestamp
|
|
72
76
|
```ruby
|
73
77
|
ts.add 1234, 3.minutes.ago # Used ActiveSupport here, but any Time object works fine
|
74
78
|
=> #<Redis::TimeSeries::Sample:0x00007fa6ce05f3f8 @time=2020-06-25 23:39:54 -0700, @value=0.1234e4>
|
79
|
+
|
80
|
+
# Optionally store data uncompressed
|
81
|
+
ts.add 5678, uncompressed: true
|
82
|
+
=> #<Redis::TimeSeries::Sample:0x00007f93f43cdf68 @time=2020-07-18 23:15:29 -0700, @value=0.5678e4>
|
75
83
|
```
|
76
84
|
Add multiple values with timestamps
|
77
85
|
```ruby
|
@@ -88,6 +96,10 @@ ts.increment # alias of incrby
|
|
88
96
|
=> 1593154255069
|
89
97
|
ts.decrement # alias of decrby
|
90
98
|
=> 1593154257344
|
99
|
+
|
100
|
+
# Optionally store data uncompressed
|
101
|
+
ts.incrby 4, uncompressed: true
|
102
|
+
=> 1595139299769
|
91
103
|
```
|
92
104
|
```ruby
|
93
105
|
ts.get
|
@@ -119,31 +131,53 @@ ts.get
|
|
119
131
|
```
|
120
132
|
Get a range of values
|
121
133
|
```ruby
|
122
|
-
|
134
|
+
# Time range as an argument
|
135
|
+
ts.range(10.minutes.ago..Time.current)
|
123
136
|
=> [#<Redis::TimeSeries::Sample:0x00007fa25f13fc28 @time=2020-06-25 23:50:51 -0700, @value=0.57e2>,
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
137
|
+
#<Redis::TimeSeries::Sample:0x00007fa25f13db58 @time=2020-06-25 23:50:55 -0700, @value=0.58e2>,
|
138
|
+
#<Redis::TimeSeries::Sample:0x00007fa25f13d900 @time=2020-06-25 23:50:57 -0700, @value=0.57e2>,
|
139
|
+
#<Redis::TimeSeries::Sample:0x00007fa25f13d680 @time=2020-06-25 23:51:30 -0700, @value=0.58e2>]
|
140
|
+
|
141
|
+
# Time range as keyword args
|
142
|
+
ts.range(from: 10.minutes.ago, to: Time.current)
|
128
143
|
=> [#<Redis::TimeSeries::Sample:0x00007fa25dc01f00 @time=2020-06-25 23:50:51 -0700, @value=0.57e2>,
|
129
|
-
|
130
|
-
|
131
|
-
|
144
|
+
#<Redis::TimeSeries::Sample:0x00007fa25dc01d20 @time=2020-06-25 23:50:55 -0700, @value=0.58e2>,
|
145
|
+
#<Redis::TimeSeries::Sample:0x00007fa25dc01b68 @time=2020-06-25 23:50:57 -0700, @value=0.57e2>,
|
146
|
+
#<Redis::TimeSeries::Sample:0x00007fa25dc019b0 @time=2020-06-25 23:51:30 -0700, @value=0.58e2>]
|
147
|
+
|
148
|
+
# Limit number of results with count argument
|
149
|
+
ts.range(10.minutes.ago..Time.current, count: 2)
|
150
|
+
=> [#<Redis::TimeSeries::Sample:0x00007fa25dc01f00 @time=2020-06-25 23:50:51 -0700, @value=0.57e2>,
|
151
|
+
#<Redis::TimeSeries::Sample:0x00007fa25dc01d20 @time=2020-06-25 23:50:55 -0700, @value=0.58e2>]
|
152
|
+
|
153
|
+
# Apply aggregations to the range
|
154
|
+
ts.range(from: 10.minutes.ago, to: Time.current, aggregation: [:avg, 10.minutes])
|
155
|
+
=> [#<Redis::TimeSeries::Sample:0x00007fa25dc01f00 @time=2020-06-25 23:50:00 -0700, @value=0.575e2>]
|
132
156
|
```
|
133
157
|
Get info about the series
|
134
158
|
```ruby
|
135
159
|
ts.info
|
136
160
|
=> #<struct Redis::TimeSeries::Info
|
161
|
+
series=
|
162
|
+
#<Redis::TimeSeries:0x00007ff46da9b578 @key="ts3", @redis=#<Redis client v4.2.1 for redis://127.0.0.1:6379/0>>,
|
137
163
|
total_samples=3,
|
138
|
-
memory_usage=
|
139
|
-
first_timestamp=
|
140
|
-
last_timestamp=
|
164
|
+
memory_usage=4264,
|
165
|
+
first_timestamp=1595187993605,
|
166
|
+
last_timestamp=1595187993629,
|
141
167
|
retention_time=0,
|
142
168
|
chunk_count=1,
|
143
169
|
max_samples_per_chunk=256,
|
144
170
|
labels={"foo"=>"bar"},
|
145
171
|
source_key=nil,
|
146
|
-
rules=
|
172
|
+
rules=
|
173
|
+
[#<Redis::TimeSeries::Rule:0x00007ff46db30c68
|
174
|
+
@aggregation=#<Redis::TimeSeries::Aggregation:0x00007ff46db30c18 @duration=3600000, @type="avg">,
|
175
|
+
@destination_key="ts1",
|
176
|
+
@source=
|
177
|
+
#<Redis::TimeSeries:0x00007ff46da9b578
|
178
|
+
@key="ts3",
|
179
|
+
@redis=#<Redis client v4.2.1 for redis://127.0.0.1:6379/0>>>]>
|
180
|
+
|
147
181
|
# Each info property is also a method on the time series object
|
148
182
|
ts.memory_usage
|
149
183
|
=> 4208
|
@@ -151,6 +185,7 @@ ts.labels
|
|
151
185
|
=> {"foo"=>"bar"}
|
152
186
|
ts.total_samples
|
153
187
|
=> 3
|
188
|
+
|
154
189
|
# Total samples also available as #count, #length, and #size
|
155
190
|
ts.count
|
156
191
|
=> 3
|
@@ -159,36 +194,140 @@ ts.length
|
|
159
194
|
ts.size
|
160
195
|
=> 3
|
161
196
|
```
|
197
|
+
Find series matching specific label(s)
|
198
|
+
```ruby
|
199
|
+
Redis::TimeSeries.query_index('foo=bar')
|
200
|
+
=> [#<Redis::TimeSeries:0x00007fc115ba1610
|
201
|
+
@key="ts3",
|
202
|
+
@redis=#<Redis client v4.2.1 for redis://127.0.0.1:6379/0>,
|
203
|
+
@retention=nil,
|
204
|
+
@uncompressed=false>]
|
205
|
+
# Note that you need at least one "label equals value" filter
|
206
|
+
Redis::TimeSeries.query_index('foo!=bar')
|
207
|
+
=> RuntimeError: Filtering requires at least one equality comparison
|
208
|
+
# query_index is also aliased as .where for fluency
|
209
|
+
Redis::TimeSeries.where('foo=bar')
|
210
|
+
=> [#<Redis::TimeSeries:0x00007fb8981010c8
|
211
|
+
@key="ts3",
|
212
|
+
@redis=#<Redis client v4.2.1 for redis://127.0.0.1:6379/0>,
|
213
|
+
@retention=nil,
|
214
|
+
@uncompressed=false>]
|
215
|
+
```
|
216
|
+
### Filter DSL
|
217
|
+
You can provide filter strings directly, per the time series documentation.
|
218
|
+
```ruby
|
219
|
+
Redis::TimeSeries.where('foo=bar')
|
220
|
+
=> [#<Redis::TimeSeries:0x00007fb8981010c8...>]
|
221
|
+
```
|
222
|
+
There is also a hash-based syntax available, which may be more pleasant to work with.
|
223
|
+
```ruby
|
224
|
+
Redis::TimeSeries.where(foo: 'bar')
|
225
|
+
=> [#<Redis::TimeSeries:0x00007fb89811dca0...>]
|
226
|
+
```
|
227
|
+
All six filter types are represented in hash format below.
|
228
|
+
```ruby
|
229
|
+
{
|
230
|
+
foo: 'bar', # label=value (equality)
|
231
|
+
foo: { not: 'bar' }, # label!=value (inequality)
|
232
|
+
foo: true, # label= (presence)
|
233
|
+
foo: false, # label!= (absence)
|
234
|
+
foo: [1, 2], # label=(1,2) (any value)
|
235
|
+
foo: { not: [1, 2] } # label!=(1,2) (no values)
|
236
|
+
}
|
237
|
+
```
|
238
|
+
Note the special use of `true` and `false`. If you're representing a boolean value with a label, rather than setting its value to "true" or "false" (which would be treated as strings in Redis anyway), you should add or remove the label from the series.
|
239
|
+
|
240
|
+
Values can be any object that responds to `.to_s`:
|
241
|
+
```ruby
|
242
|
+
class Person
|
243
|
+
def initialize(name)
|
244
|
+
@name = name
|
245
|
+
end
|
246
|
+
|
247
|
+
def to_s
|
248
|
+
@name
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
Redis::TimeSeries.where(person: Person.new('John'))
|
253
|
+
#=> TS.QUERYINDEX person=John
|
254
|
+
```
|
255
|
+
|
256
|
+
### Compaction Rules
|
257
|
+
Add a compaction rule to a series.
|
258
|
+
```ruby
|
259
|
+
# Destintation time series needs to be created before the rule is added.
|
260
|
+
other_ts = Redis::TimeSeries.create('other_ts')
|
261
|
+
|
262
|
+
# Aggregation buckets are measured in milliseconds
|
263
|
+
ts.create_rule(dest: other_ts, aggregation: [:count, 60000]) # 1 minute
|
264
|
+
|
265
|
+
# Can provide a string key instead of a time series object
|
266
|
+
ts.create_rule(dest: 'other_ts', aggregation: [:avg, 120000])
|
267
|
+
|
268
|
+
# If you're using Rails or ActiveSupport, you can provide an
|
269
|
+
# ActiveSupport::Duration instead of an integer
|
270
|
+
ts.create_rule(dest: other_ts, aggregation: [:avg, 2.minutes])
|
271
|
+
|
272
|
+
# Can also provide an Aggregation object instead of an array
|
273
|
+
agg = Redis::TimeSeries::Aggregation.new(:avg, 120000)
|
274
|
+
ts.create_rule(dest: other_ts, aggregation: agg)
|
275
|
+
|
276
|
+
# Class-level method also available
|
277
|
+
Redis::TimeSeries.create_rule(source: ts, dest: other_ts, aggregation: ['std.p', 150000])
|
278
|
+
```
|
279
|
+
Get existing compaction rules
|
280
|
+
```ruby
|
281
|
+
ts.rules
|
282
|
+
=> [#<Redis::TimeSeries::Rule:0x00007ff46e91c728
|
283
|
+
@aggregation=#<Redis::TimeSeries::Aggregation:0x00007ff46e91c6d8 @duration=3600000, @type="avg">,
|
284
|
+
@destination_key="ts1",
|
285
|
+
@source=
|
286
|
+
#<Redis::TimeSeries:0x00007ff46da9b578 @key="ts3", @redis=#<Redis client v4.2.1 for redis://127.0.0.1:6379/0>>>]
|
287
|
+
|
288
|
+
# Get properties of a rule too
|
289
|
+
ts.rules.first.aggregation
|
290
|
+
=> #<Redis::TimeSeries::Aggregation:0x00007ff46d146d38 @duration=3600000, @type="avg">
|
291
|
+
ts.rules.first.destination
|
292
|
+
=> #<Redis::TimeSeries:0x00007ff46d8a3d60 @key="ts1", @redis=#<Redis client v4.2.1 for redis://127.0.0.1:6379/0>>
|
293
|
+
```
|
294
|
+
|
295
|
+
Remove an existing compaction rule
|
296
|
+
```ruby
|
297
|
+
ts.delete_rule(dest: 'other_ts')
|
298
|
+
ts.rules.first.delete
|
299
|
+
Redis::TimeSeries.delete_rule(source: ts, dest: 'other_ts')
|
300
|
+
```
|
301
|
+
|
162
302
|
|
163
303
|
### TODO
|
164
304
|
* `TS.REVRANGE`
|
165
305
|
* `TS.MRANGE`/`TS.MREVRANGE`
|
166
|
-
* `TS.QUERYINDEX`
|
167
|
-
* Compaction rules
|
168
|
-
* Filters
|
169
306
|
* Probably a bunch more stuff
|
170
307
|
|
171
308
|
## Development
|
172
309
|
|
173
|
-
After checking out the repo, run `bin/setup
|
310
|
+
After checking out the repo, run `bin/setup`. You need the `docker` daemon installed and running. This script will:
|
311
|
+
* Install gem dependencies
|
312
|
+
* Pull the latest `redislabs/redistimeseries` image
|
313
|
+
* Start a Redis server on port 6379
|
314
|
+
* Seed three time series with some sample data
|
315
|
+
* Attach to the running server and print logs to `STDOUT`
|
174
316
|
|
175
|
-
|
176
|
-
```
|
177
|
-
docker run -p 6379:6379 -it --rm redislabs/redistimeseries
|
178
|
-
```
|
179
|
-
|
180
|
-
The `bin/console` script will set up three time series, `@ts1`, `@ts2`, and `@ts3`, with three values in each. **It will also flush the local Redis server each time you run it**, so don't try it if you have data you don't want to lose!
|
317
|
+
With the above script running, or after starting a server manually, you can run `bin/console` to interact with it. The three series are named `ts1`, `ts2`, and `ts3`, and are available as instance variables in the console.
|
181
318
|
|
182
319
|
If you want to see the commands being executed, run the console with `DEBUG=true bin/console` and it will output the raw command strings as they're executed.
|
183
320
|
```ruby
|
184
321
|
[1] pry(main)> @ts1.increment
|
185
|
-
DEBUG: TS.INCRBY
|
322
|
+
DEBUG: TS.INCRBY ts1 1
|
186
323
|
=> 1593159795467
|
187
324
|
[2] pry(main)> @ts1.get
|
188
|
-
DEBUG: TS.GET
|
325
|
+
DEBUG: TS.GET ts1
|
189
326
|
=> #<Redis::TimeSeries::Sample:0x00007f8e1a190cf8 @time=2020-06-26 01:23:15 -0700, @value=0.4e1>
|
190
327
|
```
|
191
328
|
|
329
|
+
Use `rake spec` to run the test suite.
|
330
|
+
|
192
331
|
## Contributing
|
193
332
|
|
194
333
|
Bug reports and pull requests are welcome on GitHub at https://github.com/dzunk/redis-time-series.
|
data/bin/console
CHANGED
@@ -6,15 +6,9 @@ require 'pry'
|
|
6
6
|
require 'redis'
|
7
7
|
require 'redis-time-series'
|
8
8
|
|
9
|
-
Redis.
|
10
|
-
|
11
|
-
@
|
12
|
-
@ts2 = Redis::TimeSeries.create('bar')
|
13
|
-
@ts3 = Redis::TimeSeries.create('baz')
|
14
|
-
|
9
|
+
@ts1 = Redis::TimeSeries.new('ts1')
|
10
|
+
@ts2 = Redis::TimeSeries.new('ts2')
|
11
|
+
@ts3 = Redis::TimeSeries.new('ts3')
|
15
12
|
@series = [@ts1, @ts2, @ts3]
|
16
|
-
@series.each do |ts|
|
17
|
-
3.times { ts.increment; sleep 0.01 }
|
18
|
-
end
|
19
13
|
|
20
14
|
Pry.start
|
data/bin/setup
CHANGED
@@ -1,8 +1,31 @@
|
|
1
|
-
#!/usr/bin/env
|
2
|
-
set -euo pipefail
|
3
|
-
IFS=$'\n\t'
|
4
|
-
set -vx
|
1
|
+
#!/usr/bin/env ruby
|
5
2
|
|
6
|
-
bundle install
|
3
|
+
system 'bundle install'
|
4
|
+
system 'docker pull redislabs/redistimeseries:latest'
|
5
|
+
container_id = `docker run -p 6379:6379 -dit --rm redislabs/redistimeseries`
|
6
|
+
at_exit { system "docker stop #{container_id}" }
|
7
7
|
|
8
|
-
|
8
|
+
require 'bundler/setup'
|
9
|
+
require 'active_support/core_ext/numeric/time'
|
10
|
+
require 'redis'
|
11
|
+
require 'redis-time-series'
|
12
|
+
|
13
|
+
Redis.current.flushall
|
14
|
+
ts1 = Redis::TimeSeries.create('ts1')
|
15
|
+
ts2 = Redis::TimeSeries.create('ts2')
|
16
|
+
ts3 = Redis::TimeSeries.create('ts3')
|
17
|
+
|
18
|
+
ts1.add 12, 6.minutes.ago
|
19
|
+
ts1.add 34, 4.minutes.ago
|
20
|
+
ts1.add 56, 2.minutes.ago
|
21
|
+
|
22
|
+
10.times { ts2.increment; sleep 0.01 }
|
23
|
+
|
24
|
+
ts3.labels = { foo: 'bar' }
|
25
|
+
ts3.add 1
|
26
|
+
sleep 0.01
|
27
|
+
ts3.incrby 2
|
28
|
+
sleep 0.01
|
29
|
+
ts3.decrement
|
30
|
+
|
31
|
+
system "docker logs -f #{container_id}"
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# The +TimeMsec+ module is a refinement for the +Time+ class that makes it easier
|
4
|
+
# to work with millisecond timestamps.
|
5
|
+
#
|
6
|
+
# @example
|
7
|
+
# Time.now.to_i # 1595194259
|
8
|
+
# Time.now.ts_msec # NoMethodError
|
9
|
+
#
|
10
|
+
# using TimeMsec
|
11
|
+
#
|
12
|
+
# Time.now.to_i # 1595194259
|
13
|
+
# Time.now.ts_msec # 1595194259000
|
14
|
+
#
|
15
|
+
# Time.from_msec(1595194259000) # 2020-07-19 14:30:59 -0700
|
16
|
+
module TimeMsec
|
17
|
+
refine Time do
|
18
|
+
# TODO: convert to #to_msec
|
19
|
+
def ts_msec
|
20
|
+
(to_f * 1000.0).to_i
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
refine Time.singleton_class do
|
25
|
+
def from_msec(timestamp)
|
26
|
+
at(timestamp / 1000.0)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|