skein 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 +7 -0
- data/Gemfile +9 -0
- data/Gemfile.lock +69 -0
- data/README.md +57 -0
- data/RELEASES.md +4 -0
- data/Rakefile +30 -0
- data/VERSION +1 -0
- data/bin/skein +186 -0
- data/config/.gitignore +3 -0
- data/config/skein.yml.example +11 -0
- data/lib/skein.rb +24 -0
- data/lib/skein/client.rb +51 -0
- data/lib/skein/client/publisher.rb +14 -0
- data/lib/skein/client/rpc.rb +96 -0
- data/lib/skein/client/subscriber.rb +25 -0
- data/lib/skein/client/worker.rb +51 -0
- data/lib/skein/config.rb +87 -0
- data/lib/skein/connected.rb +52 -0
- data/lib/skein/context.rb +38 -0
- data/lib/skein/handler.rb +86 -0
- data/lib/skein/handler/async.rb +9 -0
- data/lib/skein/handler/threaded.rb +7 -0
- data/lib/skein/rabbitmq.rb +44 -0
- data/lib/skein/reporter.rb +11 -0
- data/lib/skein/rpc.rb +24 -0
- data/lib/skein/rpc/base.rb +23 -0
- data/lib/skein/rpc/error.rb +34 -0
- data/lib/skein/rpc/notification.rb +2 -0
- data/lib/skein/rpc/request.rb +62 -0
- data/lib/skein/rpc/response.rb +38 -0
- data/lib/skein/support.rb +67 -0
- data/skein.gemspec +95 -0
- data/test/data/sample_config.yml +13 -0
- data/test/helper.rb +42 -0
- data/test/script/em_example +28 -0
- data/test/unit/test_skein_client.rb +18 -0
- data/test/unit/test_skein_client_publisher.rb +10 -0
- data/test/unit/test_skein_client_subscriber.rb +41 -0
- data/test/unit/test_skein_client_worker.rb +61 -0
- data/test/unit/test_skein_config.rb +33 -0
- data/test/unit/test_skein_context.rb +44 -0
- data/test/unit/test_skein_rabbitmq.rb +14 -0
- data/test/unit/test_skein_reporter.rb +4 -0
- data/test/unit/test_skein_rpc_error.rb +10 -0
- data/test/unit/test_skein_rpc_request.rb +93 -0
- data/test/unit/test_skein_support.rb +95 -0
- metadata +148 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 6896b1151e348573c5b58ee131b6f568373d7547
|
4
|
+
data.tar.gz: 4ae4f3c7de9c5eaf0d17e9e0ec77ef02390824f1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 32a30b3dc6c37ac747d372f9379f90463f0c36de086ef2eb464eedc0d5f93b8b88e8737c5d0cd3a42dcbed0ccdd0d12e43bf2ac6f4f7679527d7f2e8e8aa88cc
|
7
|
+
data.tar.gz: fb8169c2061892dbe1c2c05da18a672646e09abf773a020ccbe556cabdbc997b6c8d85548f8392a751d834dc7a13c1970e59147d7d73d58d778caa3be50cafde
|
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
GEM
|
2
|
+
remote: https://rubygems.org/
|
3
|
+
specs:
|
4
|
+
addressable (2.5.0)
|
5
|
+
public_suffix (~> 2.0, >= 2.0.2)
|
6
|
+
birling (0.1.3)
|
7
|
+
builder (3.2.2)
|
8
|
+
descendants_tracker (0.0.4)
|
9
|
+
thread_safe (~> 0.3, >= 0.3.1)
|
10
|
+
faraday (0.9.2)
|
11
|
+
multipart-post (>= 1.2, < 3)
|
12
|
+
git (1.3.0)
|
13
|
+
github_api (0.11.3)
|
14
|
+
addressable (~> 2.3)
|
15
|
+
descendants_tracker (~> 0.0.1)
|
16
|
+
faraday (~> 0.8, < 0.10)
|
17
|
+
hashie (>= 1.2)
|
18
|
+
multi_json (>= 1.7.5, < 2.0)
|
19
|
+
nokogiri (~> 1.6.0)
|
20
|
+
oauth2
|
21
|
+
hashie (3.4.6)
|
22
|
+
highline (1.7.8)
|
23
|
+
jeweler (2.1.2)
|
24
|
+
builder
|
25
|
+
bundler (>= 1.0)
|
26
|
+
git (>= 1.2.5)
|
27
|
+
github_api (~> 0.11.0)
|
28
|
+
highline (>= 1.6.15)
|
29
|
+
nokogiri (>= 1.5.10)
|
30
|
+
rake
|
31
|
+
rdoc
|
32
|
+
semver
|
33
|
+
jwt (1.5.6)
|
34
|
+
mini_portile2 (2.1.0)
|
35
|
+
multi_json (1.12.1)
|
36
|
+
multi_xml (0.5.5)
|
37
|
+
multipart-post (2.0.0)
|
38
|
+
nokogiri (1.6.8.1)
|
39
|
+
mini_portile2 (~> 2.1.0)
|
40
|
+
nokogiri (1.6.8.1-java)
|
41
|
+
oauth2 (1.2.0)
|
42
|
+
faraday (>= 0.8, < 0.10)
|
43
|
+
jwt (~> 1.0)
|
44
|
+
multi_json (~> 1.3)
|
45
|
+
multi_xml (~> 0.5)
|
46
|
+
rack (>= 1.2, < 3)
|
47
|
+
power_assert (0.3.1)
|
48
|
+
public_suffix (2.0.4)
|
49
|
+
rack (2.0.1)
|
50
|
+
rake (11.3.0)
|
51
|
+
rdoc (5.0.0)
|
52
|
+
semver (1.0.1)
|
53
|
+
test-unit (3.2.1)
|
54
|
+
power_assert
|
55
|
+
thread_safe (0.3.5)
|
56
|
+
thread_safe (0.3.5-java)
|
57
|
+
|
58
|
+
PLATFORMS
|
59
|
+
java
|
60
|
+
ruby
|
61
|
+
|
62
|
+
DEPENDENCIES
|
63
|
+
birling
|
64
|
+
jeweler
|
65
|
+
rake
|
66
|
+
test-unit
|
67
|
+
|
68
|
+
BUNDLED WITH
|
69
|
+
1.13.6
|
data/README.md
ADDED
@@ -0,0 +1,57 @@
|
|
1
|
+
# Skein
|
2
|
+
|
3
|
+
[Skein](https://en.wikipedia.org/wiki/V_formation) is a RabbitMQ-based standard
|
4
|
+
and implementation for Ruby that defines how to dispatch
|
5
|
+
[JSON-RPC](http://json-rpc.org) jobs over AMQP.
|
6
|
+
|
7
|
+
## Dependencies
|
8
|
+
|
9
|
+
This library requires an active AMQP server like [RabbitMQ](http://rabbitmq.com)
|
10
|
+
and a Ruby driver for AMQP like [Bunny](http://rubybunny.info) or
|
11
|
+
[March Hare](http://rubymarchhare.info).
|
12
|
+
|
13
|
+
Both jRuby and MRI Ruby are supported.
|
14
|
+
|
15
|
+
## Installation
|
16
|
+
|
17
|
+
The default [Bundler](http://bundler.io) configuration should be a good place
|
18
|
+
to start:
|
19
|
+
|
20
|
+
bundle install
|
21
|
+
|
22
|
+
## Configuration
|
23
|
+
|
24
|
+
For testing, set up `config/rabbitmq.yml` with configuration parameters that
|
25
|
+
define how to connect to RabbitMQ.
|
26
|
+
|
27
|
+
## Client Modes
|
28
|
+
|
29
|
+
### RPC
|
30
|
+
|
31
|
+
An RPC client can make blocking or non-blocking calls. By default calls are
|
32
|
+
blocking, but they can be made non-blocking by adding `!` to the end of the
|
33
|
+
method name. For example:
|
34
|
+
|
35
|
+
client = Skein::Client.rpc('test_queue')
|
36
|
+
|
37
|
+
client.request!(test: 'data')
|
38
|
+
|
39
|
+
client.close
|
40
|
+
|
41
|
+
Note that non-blocking calls are fire-and-forget, there is no way of knowing
|
42
|
+
if that operation succeeded or failed.
|
43
|
+
|
44
|
+
### Worker
|
45
|
+
|
46
|
+
The back-end that receives and processes RPC calls is instantiated as
|
47
|
+
a `Skein::Client::Worker` instance:
|
48
|
+
|
49
|
+
class Responder < Skein::Client::Worker
|
50
|
+
def request
|
51
|
+
{
|
52
|
+
result: true
|
53
|
+
}
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
Responder.new('test_queue')
|
data/RELEASES.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require 'rake/testtask'
|
4
|
+
|
5
|
+
# -- Jeweler ----------------------------------------------------------------
|
6
|
+
|
7
|
+
require 'jeweler'
|
8
|
+
|
9
|
+
Jeweler::Tasks.new do |gem|
|
10
|
+
gem.name = 'skein'
|
11
|
+
gem.homepage = 'http://github.com/postageapp/skein'
|
12
|
+
gem.license = 'closed'
|
13
|
+
gem.summary = %Q{RabbitMQ RPC/PubSub Library}
|
14
|
+
gem.description = %Q{Wrapper for RabbitMQ that makes blocking RPC calls and handles pub-sub broadcasts.}
|
15
|
+
gem.email = 'tadman@postageapp.com'
|
16
|
+
gem.authors = [ 'Scott Tadman' ]
|
17
|
+
end
|
18
|
+
|
19
|
+
Jeweler::RubygemsDotOrgTasks.new
|
20
|
+
|
21
|
+
# -- test/unit --------------------------------------------------------------
|
22
|
+
|
23
|
+
Rake::TestTask.new do |t|
|
24
|
+
t.libs << 'test'
|
25
|
+
t.test_files = FileList['test/**/test*.rb']
|
26
|
+
t.verbose = true
|
27
|
+
t.warning = !!ENV['RUBY_WARN']
|
28
|
+
end
|
29
|
+
|
30
|
+
task default: :test
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.3.0
|
data/bin/skein
ADDED
@@ -0,0 +1,186 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# == Imports ================================================================
|
4
|
+
|
5
|
+
require 'optparse'
|
6
|
+
require 'thread'
|
7
|
+
|
8
|
+
require_relative '../lib/skein'
|
9
|
+
|
10
|
+
# == Support Classes ========================================================
|
11
|
+
|
12
|
+
class EchoWorker < Skein::Client::Worker
|
13
|
+
def initialize(queue_name, options = nil)
|
14
|
+
super(queue_name, options || { })
|
15
|
+
|
16
|
+
@debug = options && options[:debug]
|
17
|
+
end
|
18
|
+
|
19
|
+
def echo(text)
|
20
|
+
if (@debug)
|
21
|
+
puts text
|
22
|
+
end
|
23
|
+
|
24
|
+
text
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
# == Support Methods ========================================================
|
29
|
+
|
30
|
+
def rescue_safely(options)
|
31
|
+
yield
|
32
|
+
|
33
|
+
rescue Object => e
|
34
|
+
$stderr.puts('[%s] %s' % [ e.class, e ])
|
35
|
+
|
36
|
+
if (options[:trace])
|
37
|
+
$stderr.puts(e.backtrace)
|
38
|
+
end
|
39
|
+
|
40
|
+
exit(-1)
|
41
|
+
end
|
42
|
+
|
43
|
+
def in_thread(options)
|
44
|
+
Thread.new do
|
45
|
+
begin
|
46
|
+
Thread.abort_on_exception = true
|
47
|
+
|
48
|
+
rescue_safely(options) do
|
49
|
+
yield
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# == Main ===================================================================
|
56
|
+
|
57
|
+
options = {
|
58
|
+
count: 1,
|
59
|
+
threads: 1
|
60
|
+
}
|
61
|
+
|
62
|
+
parser = OptionParser.new do |parser|
|
63
|
+
parser.on('-v', '--verbose') do
|
64
|
+
options[:verbose] = true
|
65
|
+
end
|
66
|
+
|
67
|
+
parser.on('-n', '--count=n') do |n|
|
68
|
+
options[:count] = n.to_i
|
69
|
+
end
|
70
|
+
parser.on('-c', '--threads=n') do |n|
|
71
|
+
options[:threads] = n.to_i
|
72
|
+
end
|
73
|
+
parser.on('-t', '--trace') do
|
74
|
+
options[:trace] = true
|
75
|
+
end
|
76
|
+
parser.on('-d', '--debug') do
|
77
|
+
options[:debug] = true
|
78
|
+
end
|
79
|
+
|
80
|
+
parser.on('-h', '--help') do
|
81
|
+
puts parser
|
82
|
+
exit(0)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
Skein::RabbitMQ.force_require!
|
87
|
+
|
88
|
+
args = parser.parse(*ARGV)
|
89
|
+
|
90
|
+
case (command = args.shift)
|
91
|
+
when 'config'
|
92
|
+
Skein::Support.hash_format(Skein.config).each do |line|
|
93
|
+
puts line
|
94
|
+
end
|
95
|
+
when 'test'
|
96
|
+
rescue_safely(options) do
|
97
|
+
Skein::RabbitMQ.connect
|
98
|
+
|
99
|
+
puts '[OK] Connection succeeded.'
|
100
|
+
end
|
101
|
+
when 'publish'
|
102
|
+
rescue_safely(options) do
|
103
|
+
publisher = Skein::Client.publisher('test_pubsub')
|
104
|
+
|
105
|
+
loop do
|
106
|
+
publisher << { test: Time.now.to_f }
|
107
|
+
|
108
|
+
sleep(1)
|
109
|
+
end
|
110
|
+
end
|
111
|
+
when 'subscribe'
|
112
|
+
rescue_safely(options) do
|
113
|
+
subscriber = Skein::Client.subscriber('test_pubsub')
|
114
|
+
|
115
|
+
subscriber.listen do |message, metadata|
|
116
|
+
puts metadata.inspect
|
117
|
+
puts message.inspect
|
118
|
+
end
|
119
|
+
end
|
120
|
+
when 'echo'
|
121
|
+
rescue_safely(options) do
|
122
|
+
results = Queue.new
|
123
|
+
|
124
|
+
start = Time.now
|
125
|
+
|
126
|
+
count = Hash.new(0)
|
127
|
+
|
128
|
+
tabulator = Thread.new do
|
129
|
+
loop do
|
130
|
+
v = results.pop
|
131
|
+
|
132
|
+
break if (v.nil?)
|
133
|
+
|
134
|
+
count[v] += 1
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
options[:threads].times.map do
|
139
|
+
in_thread(options) do
|
140
|
+
client = Skein::Client.new
|
141
|
+
rpc = client.rpc('test_echo')
|
142
|
+
|
143
|
+
options[:count].times do |i|
|
144
|
+
test_data = SecureRandom.uuid
|
145
|
+
|
146
|
+
response = rpc.echo(test_data)
|
147
|
+
|
148
|
+
results << (response == test_data)
|
149
|
+
|
150
|
+
if (options[:verbose])
|
151
|
+
puts '[%s] %s (%d/%d)' % [
|
152
|
+
(response == test_data ? 'OK' : 'ERR'),
|
153
|
+
response.inspect,
|
154
|
+
i + 1,
|
155
|
+
options[:count]
|
156
|
+
]
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
rpc.close
|
161
|
+
client.close
|
162
|
+
end
|
163
|
+
end.each(&:join)
|
164
|
+
|
165
|
+
results << nil
|
166
|
+
tabulator.join
|
167
|
+
|
168
|
+
elapsed = Time.now - start
|
169
|
+
|
170
|
+
puts 'Success: %d Failed: %d in %.1fms [%d mps]' % [
|
171
|
+
count[true],
|
172
|
+
count[false],
|
173
|
+
elapsed.to_f * 1000,
|
174
|
+
count[true] > 0 ? (count[true].to_f / elapsed.to_f) : 0
|
175
|
+
]
|
176
|
+
end
|
177
|
+
when 'echo_server'
|
178
|
+
rescue_safely(options) do
|
179
|
+
options[:threads].times.map do
|
180
|
+
EchoWorker.new('test_echo')
|
181
|
+
end.each(&:join)
|
182
|
+
end
|
183
|
+
else
|
184
|
+
$stderr.puts('Unknown command: %s' % command)
|
185
|
+
exit(-1)
|
186
|
+
end
|
data/config/.gitignore
ADDED
data/lib/skein.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Skein
|
4
|
+
VERSION = File.read(File.expand_path('../VERSION', File.dirname(__FILE__))).chomp.freeze
|
5
|
+
|
6
|
+
def self.version
|
7
|
+
VERSION
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.config
|
11
|
+
@config ||= Skein::Config.new
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
require_relative './skein/connected'
|
16
|
+
|
17
|
+
require_relative './skein/client'
|
18
|
+
require_relative './skein/config'
|
19
|
+
require_relative './skein/context'
|
20
|
+
require_relative './skein/handler'
|
21
|
+
require_relative './skein/rabbitmq'
|
22
|
+
require_relative './skein/reporter'
|
23
|
+
require_relative './skein/rpc'
|
24
|
+
require_relative './skein/support'
|
data/lib/skein/client.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'securerandom'
|
2
|
+
require 'fiber'
|
3
|
+
|
4
|
+
class Skein::Client < Skein::Connected
|
5
|
+
# == Properties ===========================================================
|
6
|
+
|
7
|
+
# == Class Methods ========================================================
|
8
|
+
|
9
|
+
def self.rpc(*args)
|
10
|
+
new.rpc(*args)
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.receiver(*args)
|
14
|
+
new.receiver(*args)
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.publisher(*args)
|
18
|
+
new.publisher(*args)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.subscriber(*args)
|
22
|
+
new.subscriber(*args)
|
23
|
+
end
|
24
|
+
|
25
|
+
# == Instance Methods =====================================================
|
26
|
+
|
27
|
+
def initialize(connection: nil, context: nil)
|
28
|
+
super(connection: connection, context: context)
|
29
|
+
end
|
30
|
+
|
31
|
+
def rpc(queue_name = nil)
|
32
|
+
Skein::Client::RPC.new(queue_name, connection: self.connection, context: self.context)
|
33
|
+
end
|
34
|
+
|
35
|
+
def receiver
|
36
|
+
Skein::Client::Receiver.new(connection: self.connection, context: self.context)
|
37
|
+
end
|
38
|
+
|
39
|
+
def publisher(queue_name)
|
40
|
+
Skein::Client::Publisher.new(queue_name, connection: self.connection, context: self.context)
|
41
|
+
end
|
42
|
+
|
43
|
+
def subscriber(queue_name, routing_key = nil)
|
44
|
+
Skein::Client::Subscriber.new(queue_name, routing_key, connection: self.connection, context: self.context)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
require_relative './client/publisher'
|
49
|
+
require_relative './client/rpc'
|
50
|
+
require_relative './client/subscriber'
|
51
|
+
require_relative './client/worker'
|