tengine_event 1.1.0 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,52 @@
1
+ require 'tengine/mq/suite'
2
+ require 'tengine/support/core_ext/enumerable/deep_freeze'
3
+
4
+ class Tengine::Mq::Suite
5
+ DEFAULT_CONFIG = {
6
+ :sender => {
7
+ :keep_connection => false,
8
+ :retry_interval => 1, # in seconds
9
+ :retry_count => 30,
10
+ },
11
+ :connection => {
12
+ :user => 'guest',
13
+ :pass => 'guest',
14
+ :vhost => '/',
15
+ :logging => false,
16
+ :insist => false,
17
+ :host => 'localhost',
18
+ :port => 5672,
19
+ :auto_reconnect_delay => 1, # in seconds
20
+ },
21
+ :channel => {
22
+ :prefetch => 1,
23
+ :auto_recovery => true,
24
+ },
25
+ :exchange => {
26
+ :name => 'tengine_event_exchange',
27
+ :type => :direct,
28
+ :passive => false,
29
+ :durable => true,
30
+ :auto_delete => false,
31
+ :internal => false,
32
+ :nowait => false,
33
+ :publish => {
34
+ :content_type => "application/json", # RFC4627
35
+ :persistent => true,
36
+ },
37
+ },
38
+ :queue => {
39
+ :name => 'tengine_event_queue',
40
+ :passive => false,
41
+ :durable => true,
42
+ :auto_delete => false,
43
+ :exclusive => false,
44
+ :nowait => false,
45
+ :subscribe => {
46
+ :ack => true,
47
+ :nowait => false,
48
+ :confirm => nil,
49
+ },
50
+ },
51
+ }.deep_freeze
52
+ end
@@ -0,0 +1,54 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require 'logger'
5
+ require'eventmachine'
6
+
7
+ __DIR__ = File.dirname(__FILE__)
8
+ base_dir = File.expand_path('../', __DIR__)
9
+ $LOAD_PATH << File.expand_path('lib', base_dir)
10
+ require 'tengine/event'
11
+
12
+ logger = Logger.new(File.expand_path("tmp/log/actual_publisher1.log", base_dir))
13
+ Tengine.logger = logger
14
+
15
+ sender = Tengine::Event::Sender.new(logger: logger, sender: {keep_connection: true} )
16
+
17
+ nest = ARGV.any?{|arg| arg =~ /^nest/ }
18
+
19
+ logger.debug("#{__FILE__}##{__LINE__}")
20
+ EM.run do
21
+
22
+ if nest
23
+
24
+ logger.debug("#{__FILE__}##{__LINE__}")
25
+ sender.fire("foo") do
26
+ logger.debug("#{__FILE__}##{__LINE__}")
27
+ sender.fire("bar") do
28
+ logger.debug("#{__FILE__}##{__LINE__}")
29
+ sender.fire("baz") do
30
+ logger.debug("#{__FILE__}##{__LINE__}")
31
+ sender.stop
32
+ logger.debug("#{__FILE__}##{__LINE__}")
33
+ end
34
+ logger.debug("#{__FILE__}##{__LINE__}")
35
+ end
36
+ logger.debug("#{__FILE__}##{__LINE__}")
37
+ end
38
+ logger.debug("#{__FILE__}##{__LINE__}")
39
+
40
+ else
41
+
42
+ logger.debug("#{__FILE__}##{__LINE__}")
43
+ sender.fire("foo")
44
+ logger.debug("#{__FILE__}##{__LINE__}")
45
+ sender.fire("bar")
46
+ logger.debug("#{__FILE__}##{__LINE__}")
47
+ sender.fire("baz")
48
+ logger.debug("#{__FILE__}##{__LINE__}")
49
+ sender.stop
50
+ logger.debug("#{__FILE__}##{__LINE__}")
51
+
52
+ end
53
+ end
54
+ logger.debug("#{__FILE__}##{__LINE__}")
@@ -0,0 +1,142 @@
1
+ #!/usr/bin/env ruby
2
+ # encoding: utf-8
3
+
4
+ require 'logger'
5
+ require'eventmachine'
6
+ require 'amqp'
7
+ require'json'
8
+
9
+ __DIR__ = File.dirname(__FILE__)
10
+ base_dir = File.expand_path('..', __DIR__)
11
+
12
+ logger = Logger.new(File.expand_path("tmp/log/actual_publisher2.log", base_dir))
13
+
14
+
15
+ nest = ARGV.any?{|arg| arg =~ /^nest/ }
16
+
17
+
18
+ logger.debug("#{__FILE__}##{__LINE__}")
19
+ EM.run do
20
+
21
+ config = {
22
+ :sender => {
23
+ :keep_connection => false,
24
+ :retry_interval => 1, # in seconds
25
+ :retry_count => 30,
26
+ },
27
+ :connection => {
28
+ :user => 'guest',
29
+ :pass => 'guest',
30
+ :vhost => '/',
31
+ :logging => false,
32
+ :insist => false,
33
+ :host => 'localhost',
34
+ :port => 5672,
35
+ :auto_reconnect_delay => 1, # in seconds
36
+ },
37
+ :channel => {
38
+ :prefetch => 1,
39
+ :auto_recovery => true,
40
+ },
41
+ :exchange => {
42
+ :name => 'tengine_event_exchange',
43
+ :type => :direct,
44
+ :passive => false,
45
+ :durable => true,
46
+ :auto_delete => false,
47
+ :internal => false,
48
+ :nowait => false,
49
+ :publish => {
50
+ :content_type => "application/json", # RFC4627
51
+ :persistent => true,
52
+ },
53
+ },
54
+ :queue => {
55
+ :name => 'tengine_event_queue',
56
+ :passive => false,
57
+ :durable => true,
58
+ :auto_delete => false,
59
+ :exclusive => false,
60
+ :nowait => false,
61
+ :subscribe => {
62
+ :ack => true,
63
+ :nowait => false,
64
+ :confirm => nil,
65
+ },
66
+ },
67
+ }
68
+
69
+ logger.debug("#{__FILE__}##{__LINE__}")
70
+ AMQP.connect(config[:connection]) do |conn|
71
+ logger.debug("#{__FILE__}##{__LINE__}")
72
+ id = AMQP::Channel.next_channel_id
73
+ AMQP::Channel.new(conn, id, config[:channel]) do |ch|
74
+ logger.debug("#{__FILE__}##{__LINE__}")
75
+ cfg = config[:exchange].dup
76
+ name = cfg.delete :name
77
+ type = cfg.delete :type
78
+ cfg.delete :publish # not needed here
79
+ AMQP::Exchange.new ch, type.intern, name, cfg do |xchg|
80
+ logger.debug("#{__FILE__}##{__LINE__}")
81
+
82
+ if nest
83
+ xchg.publish({"event_type_name" => "foo"}.to_json) do
84
+ logger.debug("#{__FILE__}##{__LINE__}")
85
+ xchg.publish({"event_type_name" => "bar"}.to_json) do
86
+ logger.debug("#{__FILE__}##{__LINE__}")
87
+ xchg.publish({"event_type_name" => "baz"}.to_json) do
88
+ logger.debug("#{__FILE__}##{__LINE__}")
89
+ conn.close{
90
+ logger.debug("#{__FILE__}##{__LINE__}")
91
+ EM.stop{
92
+ logger.debug("#{__FILE__}##{__LINE__}")
93
+ exit
94
+ logger.debug("#{__FILE__}##{__LINE__}")
95
+ }
96
+ logger.debug("#{__FILE__}##{__LINE__}")
97
+ }
98
+ logger.debug("#{__FILE__}##{__LINE__}")
99
+ end
100
+ logger.debug("#{__FILE__}##{__LINE__}")
101
+ end
102
+ logger.debug("#{__FILE__}##{__LINE__}")
103
+ end
104
+ else
105
+ xchg.publish({"event_type_name" => "foo"}.to_json)
106
+ # xchg.publish({"event_type_name" => "foo"}.to_json) do
107
+ # logger.debug("#{__FILE__}##{__LINE__}")
108
+ # end
109
+ logger.debug("#{__FILE__}##{__LINE__}")
110
+
111
+ # sleep 0.1
112
+
113
+ xchg.publish({"event_type_name" => "bar"}.to_json)
114
+
115
+ xchg.publish({"event_type_name" => "baz"}.to_json) do
116
+ logger.debug("#{__FILE__}##{__LINE__}")
117
+ conn.close{
118
+ logger.debug("#{__FILE__}##{__LINE__}")
119
+ EM.stop{
120
+ logger.debug("#{__FILE__}##{__LINE__}")
121
+ exit
122
+ logger.debug("#{__FILE__}##{__LINE__}")
123
+ }
124
+ logger.debug("#{__FILE__}##{__LINE__}")
125
+ }
126
+ logger.debug("#{__FILE__}##{__LINE__}")
127
+ end
128
+ # xchg.publish({"event_type_name" => "bar"}.to_json) do
129
+ # logger.debug("#{__FILE__}##{__LINE__}")
130
+ # end
131
+ logger.debug("#{__FILE__}##{__LINE__}")
132
+ end
133
+
134
+
135
+ end
136
+ logger.debug("#{__FILE__}##{__LINE__}")
137
+ end
138
+ logger.debug("#{__FILE__}##{__LINE__}")
139
+ end
140
+ logger.debug("#{__FILE__}##{__LINE__}")
141
+ end
142
+ logger.debug("#{__FILE__}##{__LINE__}")
@@ -0,0 +1,103 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'spec_helper'
3
+
4
+ require 'logger'
5
+ require'eventmachine'
6
+
7
+ describe "tengine_event" do
8
+
9
+ before(:all) do
10
+ TestRabbitmq.kill_remain_processes
11
+ @test_rabbitmq = TestRabbitmq.new(keep_port: true).launch
12
+ end
13
+
14
+ after(:all) do
15
+ TestRabbitmq.kill_launched_processes
16
+ end
17
+
18
+ before do
19
+ system(File.expand_path("../../bin/tengine_event_sucks", __FILE__))
20
+ end
21
+
22
+ let(:logger){ Logger.new(File.expand_path("../../tmp/log/actual_spec.log", __FILE__)) }
23
+
24
+ before{ logger.info("-" * 100) }
25
+ after(:all){ logger.info("=" * 100) }
26
+
27
+ shared_examples_for "publisher and subscriber are in same process" do |block|
28
+ let(:buffer){ [] }
29
+ let(:suite ){ Tengine::Mq::Suite.new }
30
+ let(:sender ){ Tengine::Event::Sender.new(logger: logger, sender: { keep_connection: true}) }
31
+
32
+ before do
33
+ logger.info("=" * 100)
34
+ Tengine.logger = logger
35
+ EM.run_test(timeout: 60) do # 1分はかからないと思うんだけど・・・
36
+ suite.subscribe do |header, payload|
37
+ header.ack
38
+ hash = JSON.parse(payload)
39
+ buffer << hash["event_type_name"]
40
+ end
41
+ block.call(sender)
42
+ EM.add_timer(10){ suite.stop }
43
+ end
44
+ end
45
+
46
+ it "receives foo, bar and baz" do
47
+ buffer.should =~ %w[foo bar baz]
48
+ end
49
+ end
50
+
51
+ context "sequential call" do
52
+ it_should_behave_like "publisher and subscriber are in same process", ->(sender){
53
+ sender.fire("foo")
54
+ sender.fire("bar")
55
+ sender.fire("baz")
56
+ }
57
+ end
58
+
59
+ context "nested call" do
60
+ it_should_behave_like "publisher and subscriber are in same process", ->(sender){
61
+ sender.fire("foo") do
62
+ sender.fire("bar") do
63
+ sender.fire("baz")
64
+ end
65
+ end
66
+ }
67
+ end
68
+
69
+ # 2つのイベント発火の場合には失敗したり成功したりが混じっていましたが、
70
+ # 3つのイベント発火の場合には100%失敗するので繰り返しは1回だけでOKです。
71
+ repeat = (ENV['REPEAT'] || 1).to_i
72
+ repeat.times do |idx|
73
+ context "#{idx + 1}/#{repeat} publisher is in another process" do
74
+ let(:timeout){ 10 }
75
+ let(:buffer){ [] }
76
+ let(:suite ){ Tengine::Mq::Suite.new }
77
+
78
+ before do
79
+ Tengine.logger = logger
80
+ EM.run_test do
81
+ # EM.next_tick do
82
+ # puts "now waiting 2 events in #{timeout} seconds."
83
+ # end
84
+ EM.add_timer(timeout) { suite.stop } # timeoutを設定
85
+
86
+ suite.subscribe do |header, payload|
87
+ header.ack
88
+ hash = JSON.parse(payload)
89
+ # puts hash.inspect
90
+ buffer << hash["event_type_name"]
91
+ suite.stop if buffer.length >= 3
92
+ end
93
+ cmd = File.expand_path("../actual_publisher1.rb", __FILE__)
94
+ system(cmd)
95
+ end
96
+ end
97
+
98
+ it "receives foo, bar and baz", skip_travis: true do
99
+ buffer.should =~ %w[foo bar baz]
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,144 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'spec_helper'
3
+
4
+ require 'logger'
5
+ require 'eventmachine'
6
+ require 'amqp'
7
+ require'json'
8
+
9
+ describe "amqp" do
10
+
11
+ before(:all) do
12
+ TestRabbitmq.kill_remain_processes
13
+ @test_rabbitmq = TestRabbitmq.new(keep_port: true).launch
14
+ end
15
+ after(:all) do
16
+ TestRabbitmq.kill_launched_processes
17
+ end
18
+
19
+ let(:logger){ Logger.new(File.expand_path("../../tmp/log/amqp_spec.log", __FILE__)) }
20
+
21
+ before do
22
+ system(File.expand_path("../../bin/tengine_event_sucks", __FILE__))
23
+ end
24
+
25
+ before{ logger.debug("-" * 100) }
26
+ after(:all){ logger.debug("=" * 100) }
27
+
28
+ [
29
+ ["actual_publisher1.rb sequential", {skip_travis: true}],
30
+ ["actual_publisher1.rb nested" , {skip_travis: true}],
31
+ ["actual_publisher2.rb sequential", {}],
32
+ ["actual_publisher2.rb nested" , {}],
33
+ ].each do |(publisher_command, opts)|
34
+ # 2つのイベント発火の場合には失敗したり成功したりが混じっていましたが、
35
+ # 3つのイベント発火の場合には100%失敗するので繰り返しは1回だけでOKです。
36
+ repeat = (ENV['REPEAT'] || 1).to_i
37
+ repeat.times do |idx|
38
+
39
+ context "#{idx + 1}/#{repeat} publisher is in another process with #{publisher_command}", opts do
40
+ let(:timeout){ 10 }
41
+ let(:buffer){ [] }
42
+
43
+ let(:config) do
44
+ {
45
+ :sender => {
46
+ :keep_connection => false,
47
+ :retry_interval => 1, # in seconds
48
+ :retry_count => 30,
49
+ },
50
+ :connection => {
51
+ :user => 'guest',
52
+ :pass => 'guest',
53
+ :vhost => '/',
54
+ :logging => false,
55
+ :insist => false,
56
+ :host => 'localhost',
57
+ :port => 5672,
58
+ :auto_reconnect_delay => 1, # in seconds
59
+ },
60
+ :channel => {
61
+ :prefetch => 1,
62
+ :auto_recovery => true,
63
+ },
64
+ :exchange => {
65
+ :name => 'tengine_event_exchange',
66
+ :type => :direct,
67
+ :passive => false,
68
+ :durable => true,
69
+ :auto_delete => false,
70
+ :internal => false,
71
+ :nowait => false,
72
+ :publish => {
73
+ :content_type => "application/json", # RFC4627
74
+ :persistent => true,
75
+ },
76
+ },
77
+ :queue => {
78
+ :name => 'tengine_event_queue',
79
+ :passive => false,
80
+ :durable => true,
81
+ :auto_delete => false,
82
+ :exclusive => false,
83
+ :nowait => false,
84
+ :subscribe => {
85
+ :ack => true,
86
+ :nowait => false,
87
+ :confirm => nil,
88
+ },
89
+ },
90
+ }
91
+ end
92
+
93
+ before do
94
+ EM.run_test(timeout: timeout * 3) do # timeoutの3倍あれば大丈夫でしょう
95
+ # EM.next_tick do
96
+ # puts "now waiting 2 events in #{timeout} seconds."
97
+ # end
98
+ EM.add_timer(timeout) { EM.stop } # timeoutを設定
99
+
100
+ AMQP.connect(config[:connection]) do |conn|
101
+ id = AMQP::Channel.next_channel_id
102
+ AMQP::Channel.new(conn, id, config[:channel]) do |ch|
103
+
104
+ cfg = config[:exchange].dup
105
+ name = cfg.delete :name
106
+ type = cfg.delete :type
107
+ cfg.delete :publish # not needed here
108
+ AMQP::Exchange.new ch, type.intern, name, cfg do |xchg|
109
+
110
+ cfg = config[:queue].dup
111
+ name = cfg.delete :name
112
+ ch.queue name, cfg do |que|
113
+ que.bind xchg, :nowait => false do
114
+
115
+ opts = config[:queue][:subscribe]
116
+ que.subscribe opts do |h, b|
117
+ h.ack
118
+ # puts b
119
+ hash = JSON.parse(b)
120
+ buffer << hash["event_type_name"]
121
+ conn.close{ EM.stop } if buffer.length >= 3
122
+ end
123
+
124
+ end
125
+ end
126
+
127
+ end
128
+ end
129
+ logger.debug("#{__FILE__}##{__LINE__}")
130
+ end
131
+ logger.debug("#{__FILE__}##{__LINE__}")
132
+
133
+ Process.spawn(File.expand_path("../#{publisher_command}", __FILE__))
134
+ end
135
+ end
136
+
137
+ it "receives foo, bar and baz" do
138
+ buffer.should == %w[foo bar baz]
139
+ end
140
+ end
141
+ end
142
+ end
143
+
144
+ end