em-synchrony 1.0.1 → 1.0.2
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +173 -173
- data/em-synchrony.gemspec +1 -1
- data/lib/active_record/connection_adapters/em_mysql2_adapter.rb +47 -47
- data/lib/em-synchrony.rb +1 -1
- data/lib/em-synchrony/activerecord.rb +102 -102
- data/lib/em-synchrony/amqp.rb +180 -180
- data/lib/em-synchrony/em-hiredis.rb +103 -103
- data/lib/em-synchrony/tcpsocket.rb +157 -28
- data/spec/activerecord_spec.rb +108 -108
- data/spec/amqp_spec.rb +146 -146
- data/spec/tcpsocket_spec.rb +401 -18
- data/spec/timer_spec.rb +7 -0
- metadata +10 -5
data/spec/activerecord_spec.rb
CHANGED
@@ -1,109 +1,109 @@
|
|
1
|
-
require "spec/helper/all"
|
2
|
-
require "em-synchrony/activerecord"
|
3
|
-
require "em-synchrony/fiber_iterator"
|
4
|
-
|
5
|
-
# create database widgets;
|
6
|
-
# use widgets;
|
7
|
-
# create table widgets (
|
8
|
-
# id INT NOT NULL AUTO_INCREMENT,
|
9
|
-
# title varchar(255),
|
10
|
-
# PRIMARY KEY (`id`)
|
11
|
-
# );
|
12
|
-
|
13
|
-
class Widget < ActiveRecord::Base; end;
|
14
|
-
|
15
|
-
describe "Fiberized ActiveRecord driver for mysql2" do
|
16
|
-
DELAY = 0.25
|
17
|
-
QUERY = "SELECT sleep(#{DELAY})"
|
18
|
-
|
19
|
-
def establish_connection
|
20
|
-
ActiveRecord::Base.establish_connection(
|
21
|
-
:adapter => 'em_mysql2',
|
22
|
-
:database => 'widgets',
|
23
|
-
:username => 'root',
|
24
|
-
:pool => 10
|
25
|
-
)
|
26
|
-
Widget.delete_all
|
27
|
-
end
|
28
|
-
|
29
|
-
it "should establish AR connection" do
|
30
|
-
EventMachine.synchrony do
|
31
|
-
establish_connection
|
32
|
-
|
33
|
-
result = Widget.find_by_sql(QUERY)
|
34
|
-
result.size.should eql(1)
|
35
|
-
EventMachine.stop
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
it "should fire sequential, synchronous requests within single fiber" do
|
40
|
-
EventMachine.synchrony do
|
41
|
-
establish_connection
|
42
|
-
|
43
|
-
start = now
|
44
|
-
res = []
|
45
|
-
|
46
|
-
res.push Widget.find_by_sql(QUERY)
|
47
|
-
res.push Widget.find_by_sql(QUERY)
|
48
|
-
|
49
|
-
(now - start.to_f).should be_within(DELAY * res.size * 0.15).of(DELAY * res.size)
|
50
|
-
res.size.should eql(2)
|
51
|
-
|
52
|
-
EventMachine.stop
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
it "should fire 100 requests in fibers" do
|
57
|
-
EM.synchrony do
|
58
|
-
establish_connection
|
59
|
-
EM::Synchrony::FiberIterator.new(1..100, 40).each do |i|
|
60
|
-
widget = Widget.create title: 'hi'
|
61
|
-
widget.update_attributes title: 'hello'
|
62
|
-
end
|
63
|
-
EM.stop
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
it "should create widget" do
|
68
|
-
EM.synchrony do
|
69
|
-
establish_connection
|
70
|
-
Widget.create
|
71
|
-
Widget.create
|
72
|
-
Widget.count.should eql(2)
|
73
|
-
EM.stop
|
74
|
-
end
|
75
|
-
end
|
76
|
-
|
77
|
-
it "should update widget" do
|
78
|
-
EM.synchrony do
|
79
|
-
establish_connection
|
80
|
-
ActiveRecord::Base.connection.execute("TRUNCATE TABLE widgets;")
|
81
|
-
widget = Widget.create title: 'hi'
|
82
|
-
widget.update_attributes title: 'hello'
|
83
|
-
Widget.find(widget.id).title.should eql('hello')
|
84
|
-
EM.stop
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
|
-
describe "transactions" do
|
89
|
-
it "should work properly" do
|
90
|
-
EM.synchrony do
|
91
|
-
establish_connection
|
92
|
-
EM::Synchrony::FiberIterator.new(1..50, 30).each do |i|
|
93
|
-
widget = Widget.create title: "hi#{i}"
|
94
|
-
ActiveRecord::Base.transaction do
|
95
|
-
widget.update_attributes title: "hello"
|
96
|
-
end
|
97
|
-
ActiveRecord::Base.transaction do
|
98
|
-
raise ActiveRecord::Rollback
|
99
|
-
end
|
100
|
-
end
|
101
|
-
Widget.all.each do |widget|
|
102
|
-
widget.title.should eq('hello')
|
103
|
-
end
|
104
|
-
EM.stop
|
105
|
-
end
|
106
|
-
end
|
107
|
-
end
|
108
|
-
|
1
|
+
require "spec/helper/all"
|
2
|
+
require "em-synchrony/activerecord"
|
3
|
+
require "em-synchrony/fiber_iterator"
|
4
|
+
|
5
|
+
# create database widgets;
|
6
|
+
# use widgets;
|
7
|
+
# create table widgets (
|
8
|
+
# id INT NOT NULL AUTO_INCREMENT,
|
9
|
+
# title varchar(255),
|
10
|
+
# PRIMARY KEY (`id`)
|
11
|
+
# );
|
12
|
+
|
13
|
+
class Widget < ActiveRecord::Base; end;
|
14
|
+
|
15
|
+
describe "Fiberized ActiveRecord driver for mysql2" do
|
16
|
+
DELAY = 0.25
|
17
|
+
QUERY = "SELECT sleep(#{DELAY})"
|
18
|
+
|
19
|
+
def establish_connection
|
20
|
+
ActiveRecord::Base.establish_connection(
|
21
|
+
:adapter => 'em_mysql2',
|
22
|
+
:database => 'widgets',
|
23
|
+
:username => 'root',
|
24
|
+
:pool => 10
|
25
|
+
)
|
26
|
+
Widget.delete_all
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should establish AR connection" do
|
30
|
+
EventMachine.synchrony do
|
31
|
+
establish_connection
|
32
|
+
|
33
|
+
result = Widget.find_by_sql(QUERY)
|
34
|
+
result.size.should eql(1)
|
35
|
+
EventMachine.stop
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should fire sequential, synchronous requests within single fiber" do
|
40
|
+
EventMachine.synchrony do
|
41
|
+
establish_connection
|
42
|
+
|
43
|
+
start = now
|
44
|
+
res = []
|
45
|
+
|
46
|
+
res.push Widget.find_by_sql(QUERY)
|
47
|
+
res.push Widget.find_by_sql(QUERY)
|
48
|
+
|
49
|
+
(now - start.to_f).should be_within(DELAY * res.size * 0.15).of(DELAY * res.size)
|
50
|
+
res.size.should eql(2)
|
51
|
+
|
52
|
+
EventMachine.stop
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should fire 100 requests in fibers" do
|
57
|
+
EM.synchrony do
|
58
|
+
establish_connection
|
59
|
+
EM::Synchrony::FiberIterator.new(1..100, 40).each do |i|
|
60
|
+
widget = Widget.create title: 'hi'
|
61
|
+
widget.update_attributes title: 'hello'
|
62
|
+
end
|
63
|
+
EM.stop
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should create widget" do
|
68
|
+
EM.synchrony do
|
69
|
+
establish_connection
|
70
|
+
Widget.create
|
71
|
+
Widget.create
|
72
|
+
Widget.count.should eql(2)
|
73
|
+
EM.stop
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should update widget" do
|
78
|
+
EM.synchrony do
|
79
|
+
establish_connection
|
80
|
+
ActiveRecord::Base.connection.execute("TRUNCATE TABLE widgets;")
|
81
|
+
widget = Widget.create title: 'hi'
|
82
|
+
widget.update_attributes title: 'hello'
|
83
|
+
Widget.find(widget.id).title.should eql('hello')
|
84
|
+
EM.stop
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
describe "transactions" do
|
89
|
+
it "should work properly" do
|
90
|
+
EM.synchrony do
|
91
|
+
establish_connection
|
92
|
+
EM::Synchrony::FiberIterator.new(1..50, 30).each do |i|
|
93
|
+
widget = Widget.create title: "hi#{i}"
|
94
|
+
ActiveRecord::Base.transaction do
|
95
|
+
widget.update_attributes title: "hello"
|
96
|
+
end
|
97
|
+
ActiveRecord::Base.transaction do
|
98
|
+
raise ActiveRecord::Rollback
|
99
|
+
end
|
100
|
+
end
|
101
|
+
Widget.all.each do |widget|
|
102
|
+
widget.title.should eq('hello')
|
103
|
+
end
|
104
|
+
EM.stop
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
109
|
end
|
data/spec/amqp_spec.rb
CHANGED
@@ -1,146 +1,146 @@
|
|
1
|
-
require "spec/helper/all"
|
2
|
-
|
3
|
-
describe EM::Synchrony::AMQP do
|
4
|
-
|
5
|
-
it "should yield until connection is ready" do
|
6
|
-
EM.synchrony do
|
7
|
-
connection = EM::Synchrony::AMQP.connect
|
8
|
-
connection.connected?.should be_true
|
9
|
-
EM.stop
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
it "should yield until disconnection is complete" do
|
14
|
-
EM.synchrony do
|
15
|
-
connection = EM::Synchrony::AMQP.connect
|
16
|
-
connection.disconnect
|
17
|
-
connection.connected?.should be_false
|
18
|
-
EM.stop
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
it "should yield until the channel is created" do
|
23
|
-
EM.synchrony do
|
24
|
-
connection = EM::Synchrony::AMQP.connect
|
25
|
-
channel = EM::Synchrony::AMQP::Channel.new(connection)
|
26
|
-
channel.should be_kind_of(EM::Synchrony::AMQP::Channel)
|
27
|
-
EM.stop
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
it "should yield until the queue is created" do
|
32
|
-
EM.synchrony do
|
33
|
-
connection = EM::Synchrony::AMQP.connect
|
34
|
-
channel = EM::Synchrony::AMQP::Channel.new(connection)
|
35
|
-
queue = EM::Synchrony::AMQP::Queue.new(channel, "test.em-synchrony.queue1", :auto_delete => true)
|
36
|
-
EM.stop
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
it "should yield when a queue is created from a channel" do
|
41
|
-
EM.synchrony do
|
42
|
-
connection = EM::Synchrony::AMQP.connect
|
43
|
-
channel = EM::Synchrony::AMQP::Channel.new(connection)
|
44
|
-
queue = channel.queue("test.em-synchrony.queue1", :auto_delete => true)
|
45
|
-
EM.stop
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
it "should yield until the exchange is created" do
|
50
|
-
EM.synchrony do
|
51
|
-
connection = EM::Synchrony::AMQP.connect
|
52
|
-
channel = EM::Synchrony::AMQP::Channel.new(connection)
|
53
|
-
|
54
|
-
exchange = EM::Synchrony::AMQP::Exchange.new(channel, :fanout, "test.em-synchrony.exchange")
|
55
|
-
exchange.should be_kind_of(EventMachine::Synchrony::AMQP::Exchange)
|
56
|
-
|
57
|
-
direct = channel.direct("test.em-synchrony.direct")
|
58
|
-
fanout = channel.fanout("test.em-synchrony.fanout")
|
59
|
-
topic = channel.topic("test.em-synchrony.topic")
|
60
|
-
headers = channel.headers("test.em-synchrony.headers")
|
61
|
-
|
62
|
-
direct.should be_kind_of(EventMachine::Synchrony::AMQP::Exchange)
|
63
|
-
fanout.should be_kind_of(EventMachine::Synchrony::AMQP::Exchange)
|
64
|
-
topic.should be_kind_of(EventMachine::Synchrony::AMQP::Exchange)
|
65
|
-
headers.should be_kind_of(EventMachine::Synchrony::AMQP::Exchange)
|
66
|
-
EM.stop
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
it "should publish and receive messages" do
|
71
|
-
nb_msg = 10
|
72
|
-
EM.synchrony do
|
73
|
-
connection = EM::Synchrony::AMQP.connect
|
74
|
-
channel = EM::Synchrony::AMQP::Channel.new(connection)
|
75
|
-
ex = EM::Synchrony::AMQP::Exchange.new(channel, :fanout, "test.em-synchrony.fanout")
|
76
|
-
|
77
|
-
q1 = channel.queue("test.em-synchrony.queues.1", :auto_delete => true)
|
78
|
-
q2 = channel.queue("test.em-synchrony.queues.2", :auto_delete => true)
|
79
|
-
|
80
|
-
q1.bind(ex)
|
81
|
-
q2.bind(ex)
|
82
|
-
|
83
|
-
nb_q1, nb_q2 = 0, 0
|
84
|
-
stop_cb = proc { EM.stop if nb_q1 + nb_q2 == 2 * nb_msg }
|
85
|
-
|
86
|
-
q1.subscribe do |meta, msg|
|
87
|
-
msg.should match(/^Bonjour [0-9]+/)
|
88
|
-
nb_q1 += 1
|
89
|
-
stop_cb.call
|
90
|
-
end
|
91
|
-
|
92
|
-
q2.subscribe do |meta, msg|
|
93
|
-
msg.should match(/^Bonjour [0-9]+/)
|
94
|
-
nb_q2 += 1
|
95
|
-
stop_cb.call
|
96
|
-
end
|
97
|
-
|
98
|
-
Fiber.new do
|
99
|
-
nb_msg.times do |n|
|
100
|
-
ex.publish("Bonjour #{n}")
|
101
|
-
EM::Synchrony.sleep(0.1)
|
102
|
-
end
|
103
|
-
end.resume
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
it "should handle several consumers" do
|
108
|
-
nb_msg = 10
|
109
|
-
EM.synchrony do
|
110
|
-
connection = EM::Synchrony::AMQP.connect
|
111
|
-
channel = EM::Synchrony::AMQP::Channel.new(connection)
|
112
|
-
exchange = EM::Synchrony::AMQP::Exchange.new(channel, :fanout, "test.em-synchrony.consumers.fanout")
|
113
|
-
|
114
|
-
queue = channel.queue("test.em-synchrony.consumers.queue", :auto_delete => true)
|
115
|
-
queue.bind(exchange)
|
116
|
-
|
117
|
-
cons1 = EM::Synchrony::AMQP::Consumer.new(channel, queue)
|
118
|
-
cons2 = EM::Synchrony::AMQP::Consumer.new(channel, queue)
|
119
|
-
|
120
|
-
nb_cons1, nb_cons2 = 0, 0
|
121
|
-
stop_cb = Proc.new do
|
122
|
-
if nb_cons1 + nb_cons2 == nb_msg
|
123
|
-
nb_cons1.should eq(nb_cons2)
|
124
|
-
EM.stop
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
cons1.on_delivery do |meta, msg|
|
129
|
-
msg.should match(/^Bonjour [0-9]+/)
|
130
|
-
nb_cons1 += 1
|
131
|
-
stop_cb.call
|
132
|
-
end.consume
|
133
|
-
|
134
|
-
cons2.on_delivery do |meta, msg|
|
135
|
-
msg.should match(/^Bonjour [0-9]+/)
|
136
|
-
nb_cons2 += 1
|
137
|
-
stop_cb.call
|
138
|
-
end.consume
|
139
|
-
|
140
|
-
10.times do |n|
|
141
|
-
exchange.publish("Bonjour #{n}")
|
142
|
-
EM::Synchrony.sleep(0.1)
|
143
|
-
end
|
144
|
-
end
|
145
|
-
end
|
146
|
-
end
|
1
|
+
require "spec/helper/all"
|
2
|
+
|
3
|
+
describe EM::Synchrony::AMQP do
|
4
|
+
|
5
|
+
it "should yield until connection is ready" do
|
6
|
+
EM.synchrony do
|
7
|
+
connection = EM::Synchrony::AMQP.connect
|
8
|
+
connection.connected?.should be_true
|
9
|
+
EM.stop
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should yield until disconnection is complete" do
|
14
|
+
EM.synchrony do
|
15
|
+
connection = EM::Synchrony::AMQP.connect
|
16
|
+
connection.disconnect
|
17
|
+
connection.connected?.should be_false
|
18
|
+
EM.stop
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should yield until the channel is created" do
|
23
|
+
EM.synchrony do
|
24
|
+
connection = EM::Synchrony::AMQP.connect
|
25
|
+
channel = EM::Synchrony::AMQP::Channel.new(connection)
|
26
|
+
channel.should be_kind_of(EM::Synchrony::AMQP::Channel)
|
27
|
+
EM.stop
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
it "should yield until the queue is created" do
|
32
|
+
EM.synchrony do
|
33
|
+
connection = EM::Synchrony::AMQP.connect
|
34
|
+
channel = EM::Synchrony::AMQP::Channel.new(connection)
|
35
|
+
queue = EM::Synchrony::AMQP::Queue.new(channel, "test.em-synchrony.queue1", :auto_delete => true)
|
36
|
+
EM.stop
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should yield when a queue is created from a channel" do
|
41
|
+
EM.synchrony do
|
42
|
+
connection = EM::Synchrony::AMQP.connect
|
43
|
+
channel = EM::Synchrony::AMQP::Channel.new(connection)
|
44
|
+
queue = channel.queue("test.em-synchrony.queue1", :auto_delete => true)
|
45
|
+
EM.stop
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should yield until the exchange is created" do
|
50
|
+
EM.synchrony do
|
51
|
+
connection = EM::Synchrony::AMQP.connect
|
52
|
+
channel = EM::Synchrony::AMQP::Channel.new(connection)
|
53
|
+
|
54
|
+
exchange = EM::Synchrony::AMQP::Exchange.new(channel, :fanout, "test.em-synchrony.exchange")
|
55
|
+
exchange.should be_kind_of(EventMachine::Synchrony::AMQP::Exchange)
|
56
|
+
|
57
|
+
direct = channel.direct("test.em-synchrony.direct")
|
58
|
+
fanout = channel.fanout("test.em-synchrony.fanout")
|
59
|
+
topic = channel.topic("test.em-synchrony.topic")
|
60
|
+
headers = channel.headers("test.em-synchrony.headers")
|
61
|
+
|
62
|
+
direct.should be_kind_of(EventMachine::Synchrony::AMQP::Exchange)
|
63
|
+
fanout.should be_kind_of(EventMachine::Synchrony::AMQP::Exchange)
|
64
|
+
topic.should be_kind_of(EventMachine::Synchrony::AMQP::Exchange)
|
65
|
+
headers.should be_kind_of(EventMachine::Synchrony::AMQP::Exchange)
|
66
|
+
EM.stop
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should publish and receive messages" do
|
71
|
+
nb_msg = 10
|
72
|
+
EM.synchrony do
|
73
|
+
connection = EM::Synchrony::AMQP.connect
|
74
|
+
channel = EM::Synchrony::AMQP::Channel.new(connection)
|
75
|
+
ex = EM::Synchrony::AMQP::Exchange.new(channel, :fanout, "test.em-synchrony.fanout")
|
76
|
+
|
77
|
+
q1 = channel.queue("test.em-synchrony.queues.1", :auto_delete => true)
|
78
|
+
q2 = channel.queue("test.em-synchrony.queues.2", :auto_delete => true)
|
79
|
+
|
80
|
+
q1.bind(ex)
|
81
|
+
q2.bind(ex)
|
82
|
+
|
83
|
+
nb_q1, nb_q2 = 0, 0
|
84
|
+
stop_cb = proc { EM.stop if nb_q1 + nb_q2 == 2 * nb_msg }
|
85
|
+
|
86
|
+
q1.subscribe do |meta, msg|
|
87
|
+
msg.should match(/^Bonjour [0-9]+/)
|
88
|
+
nb_q1 += 1
|
89
|
+
stop_cb.call
|
90
|
+
end
|
91
|
+
|
92
|
+
q2.subscribe do |meta, msg|
|
93
|
+
msg.should match(/^Bonjour [0-9]+/)
|
94
|
+
nb_q2 += 1
|
95
|
+
stop_cb.call
|
96
|
+
end
|
97
|
+
|
98
|
+
Fiber.new do
|
99
|
+
nb_msg.times do |n|
|
100
|
+
ex.publish("Bonjour #{n}")
|
101
|
+
EM::Synchrony.sleep(0.1)
|
102
|
+
end
|
103
|
+
end.resume
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
it "should handle several consumers" do
|
108
|
+
nb_msg = 10
|
109
|
+
EM.synchrony do
|
110
|
+
connection = EM::Synchrony::AMQP.connect
|
111
|
+
channel = EM::Synchrony::AMQP::Channel.new(connection)
|
112
|
+
exchange = EM::Synchrony::AMQP::Exchange.new(channel, :fanout, "test.em-synchrony.consumers.fanout")
|
113
|
+
|
114
|
+
queue = channel.queue("test.em-synchrony.consumers.queue", :auto_delete => true)
|
115
|
+
queue.bind(exchange)
|
116
|
+
|
117
|
+
cons1 = EM::Synchrony::AMQP::Consumer.new(channel, queue)
|
118
|
+
cons2 = EM::Synchrony::AMQP::Consumer.new(channel, queue)
|
119
|
+
|
120
|
+
nb_cons1, nb_cons2 = 0, 0
|
121
|
+
stop_cb = Proc.new do
|
122
|
+
if nb_cons1 + nb_cons2 == nb_msg
|
123
|
+
nb_cons1.should eq(nb_cons2)
|
124
|
+
EM.stop
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
cons1.on_delivery do |meta, msg|
|
129
|
+
msg.should match(/^Bonjour [0-9]+/)
|
130
|
+
nb_cons1 += 1
|
131
|
+
stop_cb.call
|
132
|
+
end.consume
|
133
|
+
|
134
|
+
cons2.on_delivery do |meta, msg|
|
135
|
+
msg.should match(/^Bonjour [0-9]+/)
|
136
|
+
nb_cons2 += 1
|
137
|
+
stop_cb.call
|
138
|
+
end.consume
|
139
|
+
|
140
|
+
10.times do |n|
|
141
|
+
exchange.publish("Bonjour #{n}")
|
142
|
+
EM::Synchrony.sleep(0.1)
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
146
|
+
end
|