ia-redis-rpc 2.0.0.pre.dev
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 +7 -0
- data/.gitignore +19 -0
- data/CHANGELOG.markdown +79 -0
- data/Gemfile +3 -0
- data/LICENSE +674 -0
- data/README.markdown +164 -0
- data/Rakefile +7 -0
- data/VERSION +1 -0
- data/build-and-publish.sh +2 -0
- data/docs/github-flavored-markdown.rb +65 -0
- data/docs/redisrpc_example.ai +1075 -1
- data/docs/redisrpc_example.png +0 -0
- data/docs/redisrpc_example.svg +329 -0
- data/examples/calc.rb +32 -0
- data/examples/client.rb +39 -0
- data/examples/server.rb +12 -0
- data/lib/redis-rpc/version.rb +3 -0
- data/lib/redis-rpc.rb +204 -0
- data/redis-rpc.gemspec +44 -0
- data/spec/calculator_spec.rb +62 -0
- data/spec/client_spec.rb +26 -0
- data/spec/kwargs_spec.rb +32 -0
- data/spec/redis-test.conf +3 -0
- data/spec/server_spec.rb +18 -0
- data/spec/spec_helper.rb +53 -0
- metadata +161 -0
data/redis-rpc.gemspec
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/redis-rpc/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = 'ia-redis-rpc'
|
6
|
+
s.version = RedisRpc::VERSION
|
7
|
+
s.license = 'GPL-3.0'
|
8
|
+
s.authors = ['Phuong Nguyen', 'Nathan Farrington']
|
9
|
+
s.email = ['nathan@nathanfarrington.com']
|
10
|
+
|
11
|
+
s.homepage = 'http://github.com/phuongnd08/redis-rpc-ruby'
|
12
|
+
s.summary = 'Lightweight RPC for Redis'
|
13
|
+
s.description = <<-DESCRIPTION
|
14
|
+
RedisRpc is the easiest to use RPC library in the world. (No small claim!).
|
15
|
+
This version is a repackage that only has Ruby implementation.
|
16
|
+
|
17
|
+
Redis is a powerful in-memory data structure server that is useful for building
|
18
|
+
fast distributed systems. Redis implements message queue functionality with its
|
19
|
+
use of list data structures and the `LPOP`, `BLPOP`, and `RPUSH` commands.
|
20
|
+
RedisRpc implements a lightweight RPC mechanism using Redis message queues to
|
21
|
+
temporarily hold RPC request and response messages. These messages are encoded
|
22
|
+
as JSON strings for portability.
|
23
|
+
|
24
|
+
Many other RPC mechanisms are either programming language specific (e.g.
|
25
|
+
Java RMI) or require boiler-plate code for explicit typing (e.g. Thrift).
|
26
|
+
RedisRpc was designed to be extremely easy to use by eliminating boiler-plate
|
27
|
+
code while also being programming language neutral. High performance was not
|
28
|
+
an initial goal of RedisRpc and other RPC libraries are likely to have better
|
29
|
+
performance. Instead, RedisRpc has better programmer performance; it lets you
|
30
|
+
get something working immediately.
|
31
|
+
DESCRIPTION
|
32
|
+
|
33
|
+
s.files = `git ls-files`.split("\n")
|
34
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
35
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
36
|
+
s.require_paths = ["lib"]
|
37
|
+
|
38
|
+
s.add_runtime_dependency 'redis'
|
39
|
+
|
40
|
+
s.add_development_dependency 'bundler'
|
41
|
+
s.add_development_dependency 'rake'
|
42
|
+
s.add_development_dependency 'rspec'
|
43
|
+
s.add_development_dependency 'byebug'
|
44
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
require_relative '../examples/calc.rb'
|
3
|
+
|
4
|
+
describe Calculator do
|
5
|
+
context "locally" do
|
6
|
+
let(:calculator) { Calculator.new }
|
7
|
+
|
8
|
+
it 'should calculate' do
|
9
|
+
expect(calculator.val).to be == 0.0
|
10
|
+
expect(calculator.add(3)).to be == 3.0
|
11
|
+
expect(calculator.sub(2)).to be == 1.0
|
12
|
+
expect(calculator.mul(14)).to be == 14.0
|
13
|
+
expect(calculator.div(7)).to be == 2.0
|
14
|
+
expect(calculator.val).to be == 2.0
|
15
|
+
expect(calculator.clr).to be == 0.0
|
16
|
+
expect(calculator.val).to be == 0.0
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'should raise when missing method is called' do
|
20
|
+
# noinspection RubyResolve
|
21
|
+
expect { calculator.a_missing_method }.to raise_error(NoMethodError)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "over rpc" do
|
26
|
+
let(:rpc_server_builder) { lambda { RedisRpc::Server.new(Redis.new($REDIS_CONFIG), 'calc', Calculator.new, logger: Logger.new(STDERR)) } }
|
27
|
+
before(:each) do
|
28
|
+
@rpc_server = Thread.start {
|
29
|
+
rpc_server_builder.call.run
|
30
|
+
}
|
31
|
+
end
|
32
|
+
after(:each) { rpc_server_builder.call.stop! && @rpc_server.kill; rpc_server_builder.call.flush_queue! }
|
33
|
+
let(:calculator) { RedisRpc::Client.new($REDIS, 'calc', timeout: 2) }
|
34
|
+
|
35
|
+
it 'should calculate' do
|
36
|
+
expect(calculator.val).to be == 0.0
|
37
|
+
expect(calculator.add(3)).to be == 3.0
|
38
|
+
expect(calculator.sub(2)).to be == 1.0
|
39
|
+
expect(calculator.mul(14)).to be == 14.0
|
40
|
+
expect(calculator.div(7)).to be == 2.0
|
41
|
+
expect(calculator.val).to be == 2.0
|
42
|
+
expect(calculator.clr).to be == 0.0
|
43
|
+
expect(calculator.val).to be == 0.0
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'should raise when missing method is called' do
|
47
|
+
# noinspection RubyResolve
|
48
|
+
expect { calculator.a_missing_method }.to raise_error(RedisRpc::RemoteException)
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'should raise timeout when execution expires' do
|
52
|
+
expect { calculator.send(:sleep, 3) }.to raise_error RedisRpc::TimeoutException
|
53
|
+
end
|
54
|
+
|
55
|
+
context "the request is executed late" do
|
56
|
+
it "won't be executed" do
|
57
|
+
allow(calculator).to receive(:get_timeout_at).and_return(Time.now.to_i - 1)
|
58
|
+
expect { calculator.val }.to raise_error(RedisRpc::RemoteException, /Expired RPC call/)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
data/spec/client_spec.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
require_relative 'spec_helper.rb'
|
2
|
+
|
3
|
+
describe RedisRpc::Client do
|
4
|
+
let(:client) { RedisRpc::Client.new($REDIS, 'example', timeout: 1) }
|
5
|
+
|
6
|
+
context "terminated" do
|
7
|
+
it "clear the backlog" do
|
8
|
+
allow($REDIS).to receive(:blpop).and_raise SignalException.new("SIGTERM")
|
9
|
+
expect {
|
10
|
+
client.perform
|
11
|
+
}.to raise_error SignalException
|
12
|
+
|
13
|
+
expect($REDIS.llen("example")).to eq 0
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
context "timeout" do
|
18
|
+
it "clear the backlog" do
|
19
|
+
expect {
|
20
|
+
client.perform
|
21
|
+
}.to raise_error RedisRpc::TimeoutException
|
22
|
+
|
23
|
+
expect($REDIS.llen("example")).to eq 0
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/spec/kwargs_spec.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
class KwargsEcho
|
4
|
+
def echo(args1, kwarg1:, kwarg2: :kwarg2)
|
5
|
+
{args1: args1, kwarg1: kwarg1, kwarg2: kwarg2}
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
describe KwargsEcho do
|
10
|
+
context "locally" do
|
11
|
+
let(:hall) { KwargsEcho.new }
|
12
|
+
|
13
|
+
it 'should echo' do
|
14
|
+
expect(hall.echo(1, kwarg1: :kw1)).to be == {args1: 1, kwarg1: :kw1, kwarg2: :kwarg2}
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
context "over rpc" do
|
19
|
+
let(:rpc_server_builder) { lambda { RedisRpc::Server.new(Redis.new($REDIS_CONFIG), 'hall', KwargsEcho.new, logger: Logger.new(STDERR)) } }
|
20
|
+
before(:each) do
|
21
|
+
@rpc_server = Thread.start {
|
22
|
+
rpc_server_builder.call.run
|
23
|
+
}
|
24
|
+
end
|
25
|
+
after(:each) { rpc_server_builder.call.stop! && @rpc_server.kill; rpc_server_builder.call.flush_queue! }
|
26
|
+
let(:hall) { RedisRpc::Client.new($REDIS, 'hall', timeout: 2) }
|
27
|
+
|
28
|
+
it 'should echo' do
|
29
|
+
expect(hall.echo(1, kwarg1: :kw1)).to be == { "args1" => 1, "kwarg1" => "kw1", "kwarg2" => "kwarg2" }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/spec/server_spec.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require_relative 'spec_helper'
|
2
|
+
|
3
|
+
describe RedisRpc::Server do
|
4
|
+
context "running" do
|
5
|
+
it "stops" do
|
6
|
+
server = RedisRpc::Server.new(Redis.new($REDIS_CONFIG), 'calc', Array.new, logger: Logger.new(STDERR))
|
7
|
+
server_thread = Thread.start {
|
8
|
+
server.run
|
9
|
+
}
|
10
|
+
expect(server_thread.stop?).to be false
|
11
|
+
expect(server_thread.alive?).to be true
|
12
|
+
|
13
|
+
expect(server.stop!).to be true
|
14
|
+
|
15
|
+
expect(server_thread.stop?).to be true
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
require 'logger'
|
3
|
+
|
4
|
+
begin
|
5
|
+
Bundler.require(:default, :development)
|
6
|
+
rescue Bundler::BundlerError => e
|
7
|
+
$stderr.puts e.message
|
8
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
9
|
+
exit e.status_code
|
10
|
+
end
|
11
|
+
|
12
|
+
RSpec.configure do |config|
|
13
|
+
config.before :suite do
|
14
|
+
raise 'redis-server must be on your path to run this test' if `which redis-server`.empty?
|
15
|
+
$REDIS_CONF_PATH = File.expand_path('../redis-test.conf', __FILE__)
|
16
|
+
|
17
|
+
redis_conf_contents = File.read($REDIS_CONF_PATH)
|
18
|
+
raise "pidfile must be specified in #{$REDIS_CONF_PATH}" unless redis_conf_contents['pidfile']
|
19
|
+
|
20
|
+
$REDIS_CONFIG = {
|
21
|
+
:host => 'localhost',
|
22
|
+
:port => (redis_conf_contents.match(/port ([0-9]+)/)[1].to_i rescue 6379),
|
23
|
+
:db => 15 # we'll be flushing regularly; db 15 is traditionally reserved for test
|
24
|
+
}
|
25
|
+
|
26
|
+
$stdout.write "Starting Redis on port #{$REDIS_CONFIG[:port]}... "; $stdout.flush
|
27
|
+
`redis-server #{$REDIS_CONF_PATH}`
|
28
|
+
puts 'Done.'
|
29
|
+
|
30
|
+
$REDIS = Redis.new($REDIS_CONFIG)
|
31
|
+
begin
|
32
|
+
$REDIS.ping
|
33
|
+
rescue Timeout::Error, Errno::ECONNREFUSED
|
34
|
+
retries ||= 3
|
35
|
+
sleep 1 and retry unless (retries -= 1).zero?
|
36
|
+
$stderr.puts 'Could not connect to Redis after 3 tries.'
|
37
|
+
exit
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
config.around :each do |example|
|
42
|
+
$REDIS.flushdb
|
43
|
+
example.call
|
44
|
+
end
|
45
|
+
|
46
|
+
config.after :suite do
|
47
|
+
pidfile = (File.read($REDIS_CONF_PATH).match(/pidfile (.+)$/)[1].chomp rescue nil)
|
48
|
+
$stdout.write "\nKilling test redis server... "; $stdout.flush
|
49
|
+
Process.kill("KILL", File.read(pidfile).chomp.to_i)
|
50
|
+
File.unlink(pidfile)
|
51
|
+
puts 'Done.'
|
52
|
+
end
|
53
|
+
end
|
metadata
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ia-redis-rpc
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.0.0.pre.dev
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Phuong Nguyen
|
8
|
+
- Nathan Farrington
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2023-03-27 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: redis
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
type: :runtime
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0'
|
28
|
+
- !ruby/object:Gem::Dependency
|
29
|
+
name: bundler
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
type: :development
|
36
|
+
prerelease: false
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
- !ruby/object:Gem::Dependency
|
43
|
+
name: rake
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
45
|
+
requirements:
|
46
|
+
- - ">="
|
47
|
+
- !ruby/object:Gem::Version
|
48
|
+
version: '0'
|
49
|
+
type: :development
|
50
|
+
prerelease: false
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
56
|
+
- !ruby/object:Gem::Dependency
|
57
|
+
name: rspec
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
59
|
+
requirements:
|
60
|
+
- - ">="
|
61
|
+
- !ruby/object:Gem::Version
|
62
|
+
version: '0'
|
63
|
+
type: :development
|
64
|
+
prerelease: false
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
|
+
requirements:
|
67
|
+
- - ">="
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: byebug
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ">="
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :development
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: '0'
|
84
|
+
description: |2
|
85
|
+
RedisRpc is the easiest to use RPC library in the world. (No small claim!).
|
86
|
+
This version is a repackage that only has Ruby implementation.
|
87
|
+
|
88
|
+
Redis is a powerful in-memory data structure server that is useful for building
|
89
|
+
fast distributed systems. Redis implements message queue functionality with its
|
90
|
+
use of list data structures and the `LPOP`, `BLPOP`, and `RPUSH` commands.
|
91
|
+
RedisRpc implements a lightweight RPC mechanism using Redis message queues to
|
92
|
+
temporarily hold RPC request and response messages. These messages are encoded
|
93
|
+
as JSON strings for portability.
|
94
|
+
|
95
|
+
Many other RPC mechanisms are either programming language specific (e.g.
|
96
|
+
Java RMI) or require boiler-plate code for explicit typing (e.g. Thrift).
|
97
|
+
RedisRpc was designed to be extremely easy to use by eliminating boiler-plate
|
98
|
+
code while also being programming language neutral. High performance was not
|
99
|
+
an initial goal of RedisRpc and other RPC libraries are likely to have better
|
100
|
+
performance. Instead, RedisRpc has better programmer performance; it lets you
|
101
|
+
get something working immediately.
|
102
|
+
email:
|
103
|
+
- nathan@nathanfarrington.com
|
104
|
+
executables: []
|
105
|
+
extensions: []
|
106
|
+
extra_rdoc_files: []
|
107
|
+
files:
|
108
|
+
- ".gitignore"
|
109
|
+
- CHANGELOG.markdown
|
110
|
+
- Gemfile
|
111
|
+
- LICENSE
|
112
|
+
- README.markdown
|
113
|
+
- Rakefile
|
114
|
+
- VERSION
|
115
|
+
- build-and-publish.sh
|
116
|
+
- docs/github-flavored-markdown.rb
|
117
|
+
- docs/redisrpc_example.ai
|
118
|
+
- docs/redisrpc_example.png
|
119
|
+
- docs/redisrpc_example.svg
|
120
|
+
- examples/calc.rb
|
121
|
+
- examples/client.rb
|
122
|
+
- examples/server.rb
|
123
|
+
- lib/redis-rpc.rb
|
124
|
+
- lib/redis-rpc/version.rb
|
125
|
+
- redis-rpc.gemspec
|
126
|
+
- spec/calculator_spec.rb
|
127
|
+
- spec/client_spec.rb
|
128
|
+
- spec/kwargs_spec.rb
|
129
|
+
- spec/redis-test.conf
|
130
|
+
- spec/server_spec.rb
|
131
|
+
- spec/spec_helper.rb
|
132
|
+
homepage: http://github.com/phuongnd08/redis-rpc-ruby
|
133
|
+
licenses:
|
134
|
+
- GPL-3.0
|
135
|
+
metadata: {}
|
136
|
+
post_install_message:
|
137
|
+
rdoc_options: []
|
138
|
+
require_paths:
|
139
|
+
- lib
|
140
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
145
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
146
|
+
requirements:
|
147
|
+
- - ">"
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: 1.3.1
|
150
|
+
requirements: []
|
151
|
+
rubygems_version: 3.3.3
|
152
|
+
signing_key:
|
153
|
+
specification_version: 4
|
154
|
+
summary: Lightweight RPC for Redis
|
155
|
+
test_files:
|
156
|
+
- spec/calculator_spec.rb
|
157
|
+
- spec/client_spec.rb
|
158
|
+
- spec/kwargs_spec.rb
|
159
|
+
- spec/redis-test.conf
|
160
|
+
- spec/server_spec.rb
|
161
|
+
- spec/spec_helper.rb
|