em-synchrony 1.0.0 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,103 @@
1
- require 'active_record'
2
- require 'em-synchrony/mysql2'
3
-
4
- require 'em-synchrony/active_record/connection_adapters/em_mysql2_adapter'
5
- require 'em-synchrony/active_record/patches'
1
+ require 'em-synchrony'
2
+ require 'active_record'
3
+ require 'active_record/connection_adapters/abstract/connection_pool'
4
+ require 'active_record/connection_adapters/abstract_adapter'
5
+ require 'em-synchrony/thread'
6
+
7
+ module ActiveRecord
8
+ module ConnectionAdapters
9
+ class ConnectionPool
10
+ def connection
11
+ _fibered_mutex.synchronize do
12
+ @reserved_connections[current_connection_id] ||= checkout
13
+ end
14
+ end
15
+
16
+ def _fibered_mutex
17
+ @fibered_mutex ||= EM::Synchrony::Thread::Mutex.new
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ module EM::Synchrony
24
+ module ActiveRecord
25
+ module Client
26
+ def open_transactions
27
+ @open_transactions ||= 0
28
+ end
29
+
30
+ def open_transactions=(v)
31
+ @open_transactions = v
32
+ end
33
+
34
+ def acquired_for_connection_pool
35
+ @acquired_for_connection_pool ||= 0
36
+ end
37
+
38
+ def acquired_for_connection_pool=(v)
39
+ @acquired_for_connection_pool = v
40
+ end
41
+ end
42
+
43
+ module Adapter
44
+ def configure_connection
45
+ nil
46
+ end
47
+
48
+ def transaction(*args, &blk)
49
+ @connection.execute(false) do |conn|
50
+ super
51
+ end
52
+ end
53
+
54
+ def real_connection
55
+ @connection.connection
56
+ end
57
+
58
+ def open_transactions
59
+ real_connection.open_transactions
60
+ end
61
+
62
+ def increment_open_transactions
63
+ real_connection.open_transactions += 1
64
+ end
65
+
66
+ def decrement_open_transactions
67
+ real_connection.open_transactions -= 1
68
+ end
69
+ end
70
+
71
+ class ConnectionPool < EM::Synchrony::ConnectionPool
72
+
73
+ # consider connection acquired
74
+ def execute(async)
75
+ f = Fiber.current
76
+ begin
77
+ conn = acquire(f)
78
+ conn.acquired_for_connection_pool += 1
79
+ yield conn
80
+ ensure
81
+ conn.acquired_for_connection_pool -= 1
82
+ release(f) if !async && conn.acquired_for_connection_pool == 0
83
+ end
84
+ end
85
+
86
+ def acquire(fiber)
87
+ return @reserved[fiber.object_id] if @reserved[fiber.object_id]
88
+ super
89
+ end
90
+
91
+ def connection
92
+ acquire(Fiber.current)
93
+ end
94
+
95
+ # via method_missing affected_rows will be recognized as async method
96
+ def affected_rows(*args, &blk)
97
+ execute(false) do |conn|
98
+ conn.send(:affected_rows, *args, &blk)
99
+ end
100
+ end
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,180 @@
1
+ begin
2
+ require "amqp"
3
+ require "amq/protocol"
4
+ rescue LoadError => error
5
+ raise "Missing EM-Synchrony dependency: gem install amqp"
6
+ end
7
+
8
+ module EventMachine
9
+ module Synchrony
10
+ module AMQP
11
+ class Error < RuntimeError; end
12
+
13
+ class << self
14
+ def sync &blk
15
+ fiber = Fiber.current
16
+ blk.call(fiber)
17
+ Fiber.yield
18
+ end
19
+
20
+ def sync_cb fiber
21
+ lambda do |*args|
22
+ if fiber == Fiber.current
23
+ return *args
24
+ else
25
+ fiber.resume *args
26
+ end
27
+ end
28
+ end
29
+
30
+ %w[connect start run].each do |type|
31
+ line = __LINE__ + 2
32
+ code = <<-EOF
33
+ def #{type}(*params)
34
+ sync { |f| ::AMQP.#{type}(*params, &sync_cb(f)) }
35
+ end
36
+ EOF
37
+ module_eval(code, __FILE__, line)
38
+ end
39
+ end
40
+
41
+ class Channel < ::AMQP::Channel
42
+ def initialize(*params, &block)
43
+ f = Fiber.current
44
+ super(*params, &EM::Synchrony::AMQP.sync_cb(f))
45
+ channel, open_ok = Fiber.yield
46
+ raise Error.new unless open_ok.is_a?(::AMQ::Protocol::Channel::OpenOk)
47
+ channel
48
+ end
49
+
50
+ %w[direct fanout topic headers].each do |type|
51
+ line = __LINE__ + 2
52
+ code = <<-EOF
53
+ alias :a#{type} :#{type}
54
+ def #{type}(name = 'amq.#{type}', opts = {})
55
+ if exchange = find_exchange(name)
56
+ extended_opts = Exchange.add_default_options(:#{type}, name, opts, nil)
57
+ validate_parameters_match!(exchange, extended_opts)
58
+ exchange
59
+ else
60
+ register_exchange(Exchange.new(self, :#{type}, name, opts))
61
+ end
62
+ end
63
+ EOF
64
+ module_eval(code, __FILE__, line)
65
+ end
66
+
67
+ alias :aqueue! :queue!
68
+ def queue!(name, opts = {})
69
+ queue = Queue.new(self, name, opts)
70
+ register_queue(queue)
71
+ end
72
+
73
+ %w[flow recover tx_select tx_commit tx_rollback reset]
74
+ .each do |type|
75
+ line = __LINE__ + 2
76
+ code = <<-EOF
77
+ alias :a#{type} :#{type}
78
+ def #{type}(*params)
79
+ EM::Synchrony::AMQP.sync { |f| self.a#{type}(*params, &EM::Synchrony::AMQP.sync_cb(f)) }
80
+ end
81
+ EOF
82
+ module_eval(code, __FILE__, line)
83
+ end
84
+ end
85
+
86
+ class Consumer < ::AMQP::Consumer
87
+ alias :aon_delivery :on_delivery
88
+ def on_delivery(&block)
89
+ Fiber.new do
90
+ aon_delivery(&EM::Synchrony::AMQP.sync_cb(Fiber.current))
91
+ loop { block.call(Fiber.yield) }
92
+ end.resume
93
+ self
94
+ end
95
+
96
+ alias :aconsume :consume
97
+ def consume(nowait = false)
98
+ ret = EM::Synchrony::AMQP.sync { |f| self.aconsume(nowait, &EM::Synchrony::AMQP.sync_cb(f)) }
99
+ raise Error.new(ret.to_s) unless ret.is_a?(::AMQ::Protocol::Basic::ConsumeOk)
100
+ self
101
+ end
102
+
103
+ alias :aresubscribe :resubscribe
104
+ def resubscribe
105
+ EM::Synchrony::AMQP.sync { |f| self.aconsume(&EM::Synchrony::AMQP.sync_cb(f)) }
106
+ self
107
+ end
108
+
109
+ alias :acancel :cancel
110
+ def cancel(nowait = false)
111
+ EM::Synchrony::AMQP.sync { |f| self.aconsume(nowait, &EM::Synchrony::AMQP.sync_cb(f)) }
112
+ self
113
+ end
114
+ end
115
+
116
+ class Exchange < ::AMQP::Exchange
117
+ def initialize(channel, type, name, opts = {}, &block)
118
+ f = Fiber.current
119
+ super(channel, type, name, opts, &EM::Synchrony::AMQP.sync_cb(f))
120
+ exchange, declare_ok = Fiber.yield
121
+ raise Error.new unless declare_ok.is_a?(::AMQ::Protocol::Exchange::DeclareOk)
122
+ exchange
123
+ end
124
+
125
+ alias :apublish :publish
126
+ def publish payload, options = {}
127
+ apublish(payload, options)
128
+ end
129
+
130
+ alias :adelete :delete
131
+ def delete(opts = {})
132
+ EM::Synchrony::AMQP.sync { |f| adelete(opts, &EM::Synchrony::AMQP.sync_cb(f)) }
133
+ end
134
+ end
135
+
136
+ class Queue < ::AMQP::Queue
137
+ def initialize(*params)
138
+ f = Fiber.current
139
+ super(*params, &EM::Synchrony::AMQP.sync_cb(f))
140
+ queue, declare_ok = Fiber.yield
141
+ raise Error.new unless declare_ok.is_a?(::AMQ::Protocol::Queue::DeclareOk)
142
+ queue
143
+ end
144
+
145
+ alias :asubscribe :subscribe
146
+ def subscribe &block
147
+ Fiber.new do
148
+ asubscribe(&EM::Synchrony::AMQP.sync_cb(Fiber.current))
149
+ loop { block.call(Fiber.yield) }
150
+ end.resume
151
+ end
152
+
153
+ %w[bind rebind unbind delete purge pop unsubscribe status].each do |type|
154
+ line = __LINE__ + 2
155
+ code = <<-EOF
156
+ alias :a#{type} :#{type}
157
+ def #{type}(*params)
158
+ EM::Synchrony::AMQP.sync { |f| self.a#{type}(*params, &EM::Synchrony::AMQP.sync_cb(f)) }
159
+ end
160
+ EOF
161
+ module_eval(code, __FILE__, line)
162
+ end
163
+ end
164
+
165
+ class Session < ::AMQP::Session
166
+ %w[disconnect].each do |type|
167
+ line = __LINE__ + 2
168
+ code = <<-EOF
169
+ alias :a#{type} :#{type}
170
+ def #{type}(*params)
171
+ EM::Synchrony::AMQP.sync { |f| self.a#{type}(*params, &EM::Synchrony::AMQP.sync_cb(f)) }
172
+ end
173
+ EOF
174
+ module_eval(code, __FILE__, line)
175
+ end
176
+ end
177
+ ::AMQP.client = ::EM::Synchrony::AMQP::Session
178
+ end
179
+ end
180
+ end
@@ -2,6 +2,8 @@ module EventMachine
2
2
  module Synchrony
3
3
 
4
4
  class ConnectionPool
5
+ undef :send
6
+
5
7
  def initialize(opts, &block)
6
8
  @reserved = {} # map of in-progress connections
7
9
  @available = [] # pool of free connections
@@ -32,7 +34,6 @@ module EventMachine
32
34
  # - if connection is available, pass it back to the calling block
33
35
  # - if pool is full, yield the current fiber until connection is available
34
36
  def acquire(fiber)
35
-
36
37
  if conn = @available.pop
37
38
  @reserved[fiber.object_id] = conn
38
39
  conn
@@ -66,7 +67,7 @@ module EventMachine
66
67
  async = (method[0,1] == "a")
67
68
 
68
69
  execute(async) do |conn|
69
- df = conn.send(method, *args, &blk)
70
+ df = conn.__send__(method, *args, &blk)
70
71
 
71
72
  if async
72
73
  fiber = Fiber.current
@@ -0,0 +1,10 @@
1
+ module Kernel
2
+ if !self.methods.include?(:silence_warnings)
3
+ def silence_warnings
4
+ old_verbose, $VERBOSE = $VERBOSE, nil
5
+ yield
6
+ ensure
7
+ $VERBOSE = old_verbose
8
+ end
9
+ end
10
+ end
@@ -1,24 +1,103 @@
1
- begin
2
- require 'em-hiredis'
3
- rescue LoadError => error
4
- raise 'Missing EM-Synchrony dependency: gem install em-hiredis'
5
- end
6
-
7
- module EventMachine
8
- module Hiredis
9
- class Connection
10
- attr_reader :connected
11
-
12
- def self.connect(host = 'localhost', port = 6379)
13
- conn = new(host, port)
14
- EM::Synchrony.sync conn
15
- conn
16
- end
17
-
18
- alias :old_method_missing :method_missing
19
- def method_missing(sym, *args)
20
- EM::Synchrony.sync old_method_missing(sym, *args)
21
- end
22
- end
23
- end
24
- end
1
+ begin
2
+ require 'em-hiredis'
3
+ rescue LoadError => error
4
+ raise 'Missing EM-Synchrony dependency: gem install em-hiredis'
5
+ end
6
+
7
+ module EventMachine
8
+ module Hiredis
9
+
10
+ def self.connect(uri = nil)
11
+ client = setup(uri)
12
+ EM::Synchrony.sync client.connect
13
+ client
14
+ end
15
+
16
+ class Client
17
+ def self.connect(host = 'localhost', port = 6379)
18
+ conn = new(host, port)
19
+ EM::Synchrony.sync conn.connect
20
+ conn
21
+ end
22
+
23
+ def connect
24
+ @connection = EM.connect(@host, @port, Connection, @host, @port)
25
+
26
+ @connection.on(:closed) do
27
+ if @connected
28
+ @defs.each { |d| d.fail("Redis disconnected") }
29
+ @defs = []
30
+ @deferred_status = nil
31
+ @connected = false
32
+ unless @closing_connection
33
+ @reconnecting = true
34
+ reconnect
35
+ end
36
+ else
37
+ unless @closing_connection
38
+ EM.add_timer(1) { reconnect }
39
+ end
40
+ end
41
+ end
42
+
43
+ @connection.on(:connected) do
44
+ Fiber.new do
45
+ @connected = true
46
+
47
+ auth(@password) if @password
48
+ select(@db) if @db
49
+
50
+ @subs.each { |s| method_missing(:subscribe, s) }
51
+ @psubs.each { |s| method_missing(:psubscribe, s) }
52
+ succeed
53
+
54
+ if @reconnecting
55
+ @reconnecting = false
56
+ emit(:reconnected)
57
+ end
58
+ end.resume
59
+ end
60
+
61
+ @connection.on(:message) do |reply|
62
+ if RuntimeError === reply
63
+ raise "Replies out of sync: #{reply.inspect}" if @defs.empty?
64
+ deferred = @defs.shift
65
+ deferred.fail(reply) if deferred
66
+ else
67
+ if reply && PUBSUB_MESSAGES.include?(reply[0]) # reply can be nil
68
+ kind, subscription, d1, d2 = *reply
69
+
70
+ case kind.to_sym
71
+ when :message
72
+ emit(:message, subscription, d1)
73
+ when :pmessage
74
+ emit(:pmessage, subscription, d1, d2)
75
+ end
76
+ else
77
+ if @defs.empty?
78
+ if @monitoring
79
+ emit(:monitor, reply)
80
+ else
81
+ raise "Replies out of sync: #{reply.inspect}"
82
+ end
83
+ else
84
+ deferred = @defs.shift
85
+ deferred.succeed(reply) if deferred
86
+ end
87
+ end
88
+ end
89
+ end
90
+
91
+ @connected = false
92
+ @reconnecting = false
93
+
94
+ return self
95
+ end
96
+
97
+ alias :old_method_missing :method_missing
98
+ def method_missing(sym, *args)
99
+ EM::Synchrony.sync old_method_missing(sym, *args)
100
+ end
101
+ end
102
+ end
103
+ end