redis_stream 0.2.1 → 0.3.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/Gemfile.lock +17 -4
- data/README.md +22 -38
- data/lib/redis_stream.rb +12 -3
- data/lib/redis_stream/consumer.rb +35 -0
- data/lib/redis_stream/group.rb +20 -38
- data/lib/redis_stream/stream.rb +37 -28
- data/lib/redis_stream/version.rb +1 -1
- data/redis_stream.gemspec +10 -8
- metadata +10 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4f61cf214e2178d4b843245af1622d226b9636903c17308de97ccfc0bd75bab3
|
4
|
+
data.tar.gz: dbc74cb1808d5838fa4d26de5c86669f35d292b207e900f6aaf45d55e62ce06a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a83b7e3985d5f30f3a66e35bd32d8d8dfe55f89ddb1d77af8354981f4419beab642e26732f3c2b0775694a0a23602ee25fc63ae0321b1a9c7891fb5e5c423b03
|
7
|
+
data.tar.gz: 57b88bc65f63499cc5c372bd94e14b1a6b3236203479b2f59b98942fc118c252ba542f0fa2003c7e62e00c005f68e2596969794f875b23f267403db7bfd702f7
|
data/Gemfile.lock
CHANGED
@@ -1,30 +1,43 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
redis_stream (0.
|
4
|
+
redis_stream (0.3.0)
|
5
5
|
redis (~> 4.1)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
10
|
coderay (1.1.2)
|
11
|
+
diff-lcs (1.3)
|
11
12
|
method_source (0.9.2)
|
12
|
-
minitest (5.13.0)
|
13
13
|
pry (0.12.2)
|
14
14
|
coderay (~> 1.1.0)
|
15
15
|
method_source (~> 0.9.0)
|
16
16
|
rake (13.0.1)
|
17
|
-
redis (4.1
|
17
|
+
redis (4.2.1)
|
18
|
+
rspec (3.9.0)
|
19
|
+
rspec-core (~> 3.9.0)
|
20
|
+
rspec-expectations (~> 3.9.0)
|
21
|
+
rspec-mocks (~> 3.9.0)
|
22
|
+
rspec-core (3.9.2)
|
23
|
+
rspec-support (~> 3.9.3)
|
24
|
+
rspec-expectations (3.9.2)
|
25
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
26
|
+
rspec-support (~> 3.9.0)
|
27
|
+
rspec-mocks (3.9.1)
|
28
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
29
|
+
rspec-support (~> 3.9.0)
|
30
|
+
rspec-support (3.9.3)
|
18
31
|
|
19
32
|
PLATFORMS
|
20
33
|
ruby
|
21
34
|
|
22
35
|
DEPENDENCIES
|
23
36
|
bundler (~> 1.17)
|
24
|
-
minitest (~> 5.0)
|
25
37
|
pry (~> 0.12)
|
26
38
|
rake (~> 13.0)
|
27
39
|
redis_stream!
|
40
|
+
rspec (~> 3.9)
|
28
41
|
|
29
42
|
BUNDLED WITH
|
30
43
|
1.17.3
|
data/README.md
CHANGED
@@ -5,10 +5,6 @@
|
|
5
5
|
<a href="https://codeclimate.com/github/tomorrowhq/redis-stream/test_coverage"><img src="https://api.codeclimate.com/v1/badges/73f0d460cf35b758e624/test_coverage" /></a>
|
6
6
|
</p>
|
7
7
|
|
8
|
-
## Status
|
9
|
-
|
10
|
-
Currently project is under active development.
|
11
|
-
|
12
8
|
## Usage
|
13
9
|
|
14
10
|
### Setting up
|
@@ -18,19 +14,9 @@ out of the box if you are using redis. It will be using same `REDIS_URL`
|
|
18
14
|
environment variable to establish connection with Redis.
|
19
15
|
|
20
16
|
```ruby
|
21
|
-
|
22
|
-
|
23
|
-
client = RedisStream.new
|
24
|
-
```
|
25
|
-
|
26
|
-
When you need to have control over redis connection you can pass redis instance
|
27
|
-
in initializer.
|
28
|
-
|
29
|
-
```ruby
|
30
|
-
require 'redis_stream'
|
17
|
+
# Gemfile
|
31
18
|
|
32
|
-
|
33
|
-
client = RedisStream.new(redis)
|
19
|
+
gem "redis_stream", "~> 0.3.0"
|
34
20
|
```
|
35
21
|
|
36
22
|
### Adding messages to the stream
|
@@ -38,38 +24,36 @@ client = RedisStream.new(redis)
|
|
38
24
|
```ruby
|
39
25
|
require 'redis_stream'
|
40
26
|
|
41
|
-
|
42
|
-
|
43
|
-
weather_stream = client.stream('weather')
|
27
|
+
daily_temperature = RedisStream.stream(name: "daily_temperature")
|
44
28
|
|
45
|
-
|
46
|
-
|
47
|
-
|
29
|
+
daily_temperature << 20.0
|
30
|
+
daily_temperature << 21.0
|
31
|
+
daily_temperature << 22.0
|
48
32
|
|
49
|
-
puts
|
33
|
+
puts daily_temperature.size
|
50
34
|
#=> 3
|
51
35
|
```
|
52
36
|
|
53
37
|
### Consuming messages from the stream
|
54
38
|
|
55
|
-
|
56
|
-
require 'redis_stream'
|
57
|
-
|
58
|
-
client = RedisStream.new
|
59
|
-
messages_stream = client.stream('messages')
|
60
|
-
|
61
|
-
messages_stream.add({ msg: 'Message 1' })
|
62
|
-
messages_stream.add({ msg: 'Message 2' })
|
39
|
+
Stream implements most of operations that can be performed on ruby Array.
|
63
40
|
|
64
|
-
|
41
|
+
```ruby
|
42
|
+
daily_temperature.each do |temperature|
|
65
43
|
puts message
|
66
44
|
end
|
67
|
-
# =>
|
68
|
-
# =>
|
45
|
+
# => 20.0
|
46
|
+
# => 21.0
|
47
|
+
# => 22.0
|
48
|
+
|
49
|
+
puts daily_temperature.last
|
50
|
+
# => 22.0
|
69
51
|
|
70
|
-
puts
|
71
|
-
# =>
|
52
|
+
puts daily_temperature.first
|
53
|
+
# => 20.0
|
72
54
|
|
73
|
-
|
74
|
-
|
55
|
+
average = daily_temperature.sum / daily_temperature.length
|
56
|
+
min = daily_temperature.min
|
57
|
+
max = daily_temperature.max
|
58
|
+
puts "Average: #{average} Min: #{min} Max: #{max}"
|
75
59
|
```
|
data/lib/redis_stream.rb
CHANGED
@@ -2,13 +2,22 @@ require 'redis'
|
|
2
2
|
require 'redis_stream/version'
|
3
3
|
require 'redis_stream/group'
|
4
4
|
require 'redis_stream/stream'
|
5
|
+
require 'redis_stream/consumer'
|
5
6
|
require 'redis_stream/client'
|
6
7
|
|
7
8
|
module RedisStream
|
8
9
|
class Error < StandardError; end
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
# @param name <String> Name of a stream
|
12
|
+
# @return <RedisStream::Stream>
|
13
|
+
def self.stream(name:)
|
14
|
+
Stream.new(name: name)
|
15
|
+
end
|
16
|
+
|
17
|
+
# @param name <String> Name of a group
|
18
|
+
# @param stream <RedisStream::Stream> Stream that group should consume
|
19
|
+
# @return <RedisStream::Group>
|
20
|
+
def self.group(name:, stream:)
|
21
|
+
Group.new(name: name, stream: stream)
|
13
22
|
end
|
14
23
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module RedisStream
|
2
|
+
class Consumer
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
attr_reader :name, :group, :stream
|
6
|
+
|
7
|
+
def initialize(name:, group:, stream:)
|
8
|
+
@name = name
|
9
|
+
@group = group
|
10
|
+
@stream = stream
|
11
|
+
end
|
12
|
+
|
13
|
+
def each(&block)
|
14
|
+
while
|
15
|
+
result = read_next
|
16
|
+
break if result.empty?
|
17
|
+
|
18
|
+
message = result[stream.name].first
|
19
|
+
id, content = message
|
20
|
+
block.call(load(content))
|
21
|
+
Redis.current.xack(stream.name, name, id)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def read_next
|
28
|
+
Redis.current.xreadgroup(group.name, name, stream.name, '>', count: 1)
|
29
|
+
end
|
30
|
+
|
31
|
+
def load(message_content)
|
32
|
+
Marshal.load(message_content["value"])
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/redis_stream/group.rb
CHANGED
@@ -1,54 +1,36 @@
|
|
1
1
|
module RedisStream
|
2
2
|
class Group
|
3
|
-
attr_reader :
|
3
|
+
attr_reader :name, :stream
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
5
|
+
# @param name <String>
|
6
|
+
# @param stream <RedisStream::Stream>
|
7
|
+
# @return RedisStream::Group
|
8
|
+
def initialize(name:, stream:)
|
8
9
|
@name = name
|
9
|
-
@
|
10
|
-
end
|
11
|
-
|
12
|
-
# Creates group and stream if group does not exist.
|
13
|
-
# @return [Group]
|
14
|
-
def create
|
15
|
-
if info.nil?
|
16
|
-
@redis.xgroup(:create, key, name, @last_delivered_id, mkstream: true)
|
17
|
-
end
|
18
|
-
|
19
|
-
self
|
20
|
-
end
|
10
|
+
@stream = stream
|
21
11
|
|
22
|
-
|
23
|
-
def destroy
|
24
|
-
@redis.xgroup(:destroy, key, name)
|
25
|
-
self
|
12
|
+
create_group
|
26
13
|
end
|
27
14
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
15
|
+
# @param name <String> Consumer name
|
16
|
+
# @return <RedisStream::Consumer>
|
17
|
+
def consumer(name)
|
18
|
+
RedisStream::Consumer.new(name: name, group: self, stream: stream)
|
32
19
|
end
|
33
20
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
messages = result[key]
|
40
|
-
messages.each do |message|
|
41
|
-
id, entry = message
|
42
|
-
yield(entry)
|
43
|
-
@redis.xack(key, name, id) if ack
|
44
|
-
end
|
45
|
-
end
|
21
|
+
# Resets group's next id on the stream
|
22
|
+
def reset(id = "0")
|
23
|
+
Redis.current.xgroup(:setid, stream.name, name, id)
|
24
|
+
self
|
46
25
|
end
|
47
26
|
|
48
27
|
private
|
49
28
|
|
50
|
-
def
|
51
|
-
|
29
|
+
def create_group
|
30
|
+
Redis.current.xgroup(
|
31
|
+
:create, stream.name, name, "$", mkstream: true)
|
32
|
+
rescue Redis::CommandError
|
33
|
+
nil
|
52
34
|
end
|
53
35
|
end
|
54
36
|
end
|
data/lib/redis_stream/stream.rb
CHANGED
@@ -1,53 +1,62 @@
|
|
1
1
|
module RedisStream
|
2
2
|
class Stream
|
3
|
-
|
3
|
+
include Enumerable
|
4
4
|
|
5
|
-
|
6
|
-
@key = key
|
7
|
-
@redis = redis
|
8
|
-
end
|
5
|
+
attr_reader :name
|
9
6
|
|
10
|
-
def
|
11
|
-
@
|
7
|
+
def initialize(name:)
|
8
|
+
@name = name
|
9
|
+
@values = []
|
12
10
|
end
|
13
11
|
|
14
|
-
def
|
15
|
-
|
12
|
+
def <<(value)
|
13
|
+
Redis.current.xadd(name, dump(value))
|
14
|
+
self
|
16
15
|
end
|
16
|
+
alias_method :push, :<<
|
17
17
|
|
18
18
|
def clear
|
19
|
-
|
19
|
+
Redis.current.xtrim(name, 0)
|
20
20
|
end
|
21
21
|
|
22
|
-
def
|
23
|
-
|
22
|
+
def last(count = 1)
|
23
|
+
messages = Redis.current.xrevrange(name, '+', '-', count: count)
|
24
|
+
messages.reverse!
|
25
|
+
|
26
|
+
result = messages.map do |message|
|
27
|
+
_id, content = message
|
28
|
+
load(content)
|
29
|
+
end
|
30
|
+
|
31
|
+
count == 1 ? result.first : result
|
24
32
|
end
|
25
33
|
|
26
|
-
def
|
27
|
-
|
34
|
+
def length
|
35
|
+
Redis.current.xlen(name)
|
36
|
+
end
|
37
|
+
alias_method :size, :length
|
38
|
+
|
39
|
+
def each(&block)
|
40
|
+
current_message_id = "0"
|
28
41
|
|
29
42
|
while
|
30
|
-
result =
|
43
|
+
result = Redis.current.xread(name, current_message_id, count: 1)
|
31
44
|
break if result.empty?
|
32
45
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
yield(entry)
|
37
|
-
end
|
46
|
+
message = result[name].first
|
47
|
+
current_message_id, message_content = message
|
48
|
+
block.call(load(message_content))
|
38
49
|
end
|
39
50
|
end
|
40
51
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
52
|
+
private
|
53
|
+
|
54
|
+
def dump(value)
|
55
|
+
{ value: Marshal.dump(value) }
|
45
56
|
end
|
46
57
|
|
47
|
-
|
48
|
-
|
49
|
-
_id, entry = @redis.xrange(key, '-', '+', count: 1).first
|
50
|
-
entry
|
58
|
+
def load(message_content)
|
59
|
+
Marshal.load(message_content["value"])
|
51
60
|
end
|
52
61
|
end
|
53
62
|
end
|
data/lib/redis_stream/version.rb
CHANGED
data/redis_stream.gemspec
CHANGED
@@ -10,7 +10,7 @@ Gem::Specification.new do |spec|
|
|
10
10
|
spec.email = ['choixer@gmail.com']
|
11
11
|
|
12
12
|
spec.summary = %q{Interface around Redis Streams for Ruby}
|
13
|
-
spec.description = %q{
|
13
|
+
spec.description = %q{Make Redis Streams feel like a first-class citizen in Ruby}
|
14
14
|
spec.homepage = 'https://github.com/antonvolkoff/redis-stream'
|
15
15
|
|
16
16
|
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
@@ -28,17 +28,19 @@ Gem::Specification.new do |spec|
|
|
28
28
|
|
29
29
|
# Specify which files should be added to the gem when it is released.
|
30
30
|
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
31
|
-
spec.files
|
32
|
-
`git ls-files -z`.split("\x0").reject
|
31
|
+
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
32
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
33
|
+
f.match(%r{^(test|spec|features|examples)/})
|
34
|
+
end
|
33
35
|
end
|
34
36
|
# spec.bindir = "exe"
|
35
37
|
# spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
36
38
|
spec.require_paths = ['lib']
|
37
39
|
|
38
|
-
spec.add_dependency
|
40
|
+
spec.add_dependency "redis", "~> 4.1"
|
39
41
|
|
40
|
-
spec.add_development_dependency
|
41
|
-
spec.add_development_dependency
|
42
|
-
spec.add_development_dependency
|
43
|
-
spec.add_development_dependency
|
42
|
+
spec.add_development_dependency "bundler", "~> 1.17"
|
43
|
+
spec.add_development_dependency "rake", "~> 13.0"
|
44
|
+
spec.add_development_dependency "pry", "~> 0.12"
|
45
|
+
spec.add_development_dependency "rspec", "~> 3.9"
|
44
46
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: redis_stream
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Anton Volkov
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-06-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|
@@ -53,34 +53,34 @@ dependencies:
|
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '13.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
56
|
+
name: pry
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
59
|
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
|
-
version: '
|
61
|
+
version: '0.12'
|
62
62
|
type: :development
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
66
|
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: '
|
68
|
+
version: '0.12'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
-
name:
|
70
|
+
name: rspec
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
73
|
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
|
-
version: '
|
75
|
+
version: '3.9'
|
76
76
|
type: :development
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
|
-
version: '
|
83
|
-
description:
|
82
|
+
version: '3.9'
|
83
|
+
description: Make Redis Streams feel like a first-class citizen in Ruby
|
84
84
|
email:
|
85
85
|
- choixer@gmail.com
|
86
86
|
executables: []
|
@@ -99,6 +99,7 @@ files:
|
|
99
99
|
- docker-compose.yml
|
100
100
|
- lib/redis_stream.rb
|
101
101
|
- lib/redis_stream/client.rb
|
102
|
+
- lib/redis_stream/consumer.rb
|
102
103
|
- lib/redis_stream/group.rb
|
103
104
|
- lib/redis_stream/stream.rb
|
104
105
|
- lib/redis_stream/version.rb
|