Class: FiberConnectionPool

Inherits:
Object
  • Object
show all
Defined in:
lib/fiber_connection_pool.rb

Constant Summary collapse

VERSION =
'0.2.4'
RESERVED_TTL_SECS =

reserved cleanup trigger

30
SAVED_DATA_TTL_SECS =

saved_data cleanup trigger

30

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts) ⇒ FiberConnectionPool

Initializes the pool with ‘size’ instances running the given block to get each one. Ex:

pool = FiberConnectionPool.new(:size => 5) { MyConnection.new }

Raises:

  • (ArgumentError)


17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/fiber_connection_pool.rb', line 17

def initialize(opts)
  raise ArgumentError.new('size > 0 is mandatory') if opts[:size].to_i <= 0

  @saved_data = {} # placeholder for requested save data
  @reserved  = {}   # map of in-progress connections
  @treated_exceptions = [ PlaceholderException ]  # list of Exception classes that need further connection treatment
  @last_reserved_cleanup = Time.now # reserved cleanup trigger
  @available = []   # pool of free connections
  @pending   = []   # pending reservations (FIFO)
  @save_data_requests = {} # blocks to be yielded to save data
  @last_data_cleanup = Time.now # saved_data cleanup trigger

  @available = Array.new(opts[:size].to_i) { yield }
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &blk) ⇒ Object (private)

Allow the pool to behave as the underlying connection

Yield the connection within execute method and release once it is complete (assumption: fiber will yield while waiting for IO, allowing the reactor run other fibers)



229
230
231
232
233
# File 'lib/fiber_connection_pool.rb', line 229

def method_missing(method, *args, &blk)
  execute(method) do |conn|
    conn.send(method, *args, &blk)
  end
end

Instance Attribute Details

#saved_dataObject

Returns the value of attribute saved_data.



10
11
12
# File 'lib/fiber_connection_pool.rb', line 10

def saved_data
  @saved_data
end

#treated_exceptionsObject

Returns the value of attribute treated_exceptions.



10
11
12
# File 'lib/fiber_connection_pool.rb', line 10

def treated_exceptions
  @treated_exceptions
end

Instance Method Details

#clear_save_data_requestsObject

Clear any save_data requests in the pool. No data will be saved after this, unless new requests are added with #save_data.



81
82
83
# File 'lib/fiber_connection_pool.rb', line 81

def clear_save_data_requests
  @save_data_requests = {}
end

#gathered_dataObject

Return the gathered data for this fiber



74
75
76
# File 'lib/fiber_connection_pool.rb', line 74

def gathered_data
  @saved_data[Fiber.current]
end

#has_connection?(conn) ⇒ Boolean

True if the given connection is anywhere inside the pool

Returns:

  • (Boolean)


110
111
112
# File 'lib/fiber_connection_pool.rb', line 110

def has_connection?(conn)
  (@available + @reserved.values).include?(conn)
end

#query(sql, *args) ⇒ Object

Avoid method_missing stack for ‘query’



102
103
104
105
106
# File 'lib/fiber_connection_pool.rb', line 102

def query(sql, *args)
  execute('query') do |conn|
    conn.query sql, *args
  end
end

#recreate_connection(new_conn) ⇒ Object

DEPRECATED: use with_failed_connection



115
116
117
# File 'lib/fiber_connection_pool.rb', line 115

def recreate_connection(new_conn)
  with_failed_connection { new_conn }
end

#release_data(fiber) ⇒ Object

Delete any saved_data for given fiber



87
88
89
# File 'lib/fiber_connection_pool.rb', line 87

def release_data(fiber)
  @saved_data.delete(fiber)
end

#reserved_cleanupObject

Delete any reserved held for dead fibers



140
141
142
143
144
145
# File 'lib/fiber_connection_pool.rb', line 140

def reserved_cleanup
  @last_reserved_cleanup = Time.now
  @reserved.dup.each do |k,v|
    release(k) if not k.alive?
  end
end

#save_data(key, &block) ⇒ Object

Add a save_data request to the pool. The given block will be executed after each successful call to -any- method on the connection. The connection and the method name are passed to the block.

The returned value will be saved in pool.saved_data[key], and will be kept as long as the fiber stays alive.

Ex:

# (...right after pool's creation...)
pool.save_data(:hey_or_hoo) do |conn, method|
  return 'hey' if method == 'query'
  'hoo'
end

# (...from a reactor fiber...)
myfiber = Fiber.current
pool.query('select anything from anywhere')
puts pool.saved_data[myfiber][:hey_or_hoo]
  => 'hey'

# (...eventually fiber dies...)
puts pool.saved_data[myfiber].inspect
  => nil


68
69
70
# File 'lib/fiber_connection_pool.rb', line 68

def save_data(key, &block)
  @save_data_requests[key] = block
end

#save_data_cleanupObject

Delete any saved_data held for dead fibers



93
94
95
96
97
98
# File 'lib/fiber_connection_pool.rb', line 93

def save_data_cleanup
  @saved_data.dup.each do |k,v|
    @saved_data.delete(k) if not k.alive?
  end
  @last_data_cleanup = Time.now
end

#save_data_for_fiberObject

DEPRECATED: use save_data



33
34
35
# File 'lib/fiber_connection_pool.rb', line 33

def save_data_for_fiber
  nil
end

#stop_saving_data_for_fiberObject

DEPRECATED: use release_data



38
39
40
# File 'lib/fiber_connection_pool.rb', line 38

def stop_saving_data_for_fiber
  @saved_data.delete Fiber.current
end

#with_failed_connectionObject

Identify the connection that just failed for current fiber. Pass it to the given block, which must return a valid instance of connection. After that, put the new connection into the pool in failed connection’s place. Raises NoReservedConnection if cannot find the failed connection instance.



124
125
126
127
128
129
130
131
132
133
134
135
136
# File 'lib/fiber_connection_pool.rb', line 124

def with_failed_connection
  bad_conn = @reserved[Fiber.current]
  raise NoReservedConnection.new if bad_conn.nil?
  new_conn = yield bad_conn
  @available.reject!{ |v| v == bad_conn }
  @reserved.reject!{ |k,v| v == bad_conn }
  @available.unshift new_conn
  # try to cleanup
  begin
    bad_conn.close
  rescue
  end
end