Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Made internal session handling, task frame and rollback request stora…

…ge thread-local.
  • Loading branch information...
commit 60c155b017e69f1e862309d9d4f6c4fc747ba054 1 parent df0935c
@roidrage roidrage authored
View
28 lib/capistrano/configuration/connections.rb
@@ -51,24 +51,26 @@ def connect_to(server)
# A hash of the SSH sessions that are currently open and available.
# Because sessions are constructed lazily, this will only contain
# connections to those servers that have been the targets of one or more
- # executed tasks.
- attr_reader :sessions
+ # executed tasks. Stored on a per-thread basis to improve thread-safety.
+ def sessions
+ Thread.current[:sessions] ||= {}
+ end
def initialize_with_connections(*args) #:nodoc:
initialize_without_connections(*args)
- @sessions = {}
- @failed_sessions = []
+ Thread.current[:sessions] = {}
+ Thread.current[:failed_sessions] = []
end
# Indicate that the given server could not be connected to.
def failed!(server)
- @failed_sessions << server
+ Thread.current[:failed_sessions] << server
end
# Query whether previous connection attempts to the given server have
# failed.
def has_failed?(server)
- @failed_sessions.include?(server)
+ Thread.current[:failed_sessions].include?(server)
end
# Used to force connections to be made to the current task's servers.
@@ -116,9 +118,9 @@ def establish_connections_to(servers)
# Destroys sessions for each server in the list.
def teardown_connections_to(servers)
servers.each do |server|
- @sessions[server].close
- @sessions.delete(server)
- end
+ sessions[server].close
+ sessions.delete(server)
+ end
end
# Determines the set of servers within the current task's scope and
@@ -186,11 +188,13 @@ def execute_on_servers(options={})
# prevents problems with the thread's scope seeing the wrong 'server'
# variable if the thread just happens to take too long to start up.
def establish_connection_to(server, failures=nil)
- Thread.new { safely_establish_connection_to(server, failures) }
+ current_thread = Thread.current
+ Thread.new { safely_establish_connection_to(server, current_thread, failures) }
end
- def safely_establish_connection_to(server, failures=nil)
- sessions[server] ||= connection_factory.connect_to(server)
+ def safely_establish_connection_to(server, thread, failures=nil)
+ thread[:sessions] ||= {}
+ thread[:sessions][server] ||= connection_factory.connect_to(server)
rescue Exception => err
raise unless failures
failures << { :server => server, :error => err }
View
37 lib/capistrano/configuration/execution.rb
@@ -8,22 +8,11 @@ def self.included(base) #:nodoc:
base.send :alias_method, :initialize, :initialize_with_execution
end
- # The call stack of the tasks. The currently executing task may inspect
- # this to see who its caller was. The current task is always the last
- # element of this stack.
- attr_reader :task_call_frames
-
- # The stack of tasks that have registered rollback handlers within the
- # current transaction. If this is nil, then there is no transaction
- # that is currently active.
- attr_reader :rollback_requests
-
# A struct for representing a single instance of an invoked task.
TaskCallFrame = Struct.new(:task, :rollback)
def initialize_with_execution(*args) #:nodoc:
initialize_without_execution(*args)
- @task_call_frames = []
end
private :initialize_with_execution
@@ -32,6 +21,25 @@ def transaction?
!rollback_requests.nil?
end
+ # The call stack of the tasks. The currently executing task may inspect
+ # this to see who its caller was. The current task is always the last
+ # element of this stack.
+ def task_call_frames
+ Thread.current[:task_call_frames] ||= []
+ end
+
+
+ # The stack of tasks that have registered rollback handlers within the
+ # current transaction. If this is nil, then there is no transaction
+ # that is currently active.
+ def rollback_requests
+ Thread.current[:rollback_requests]
+ end
+
+ def rollback_requests=(rollback_requests)
+ Thread.current[:rollback_requests] = rollback_requests
+ end
+
# Invoke a set of tasks in a transaction. If any task fails (raises an
# exception), all tasks executed within the transaction are inspected to
# see if they have an associated on_rollback hook, and if so, that hook
@@ -44,14 +52,14 @@ def transaction
logger.info "transaction: start"
begin
- @rollback_requests = []
+ self.rollback_requests = []
yield
logger.info "transaction: commit"
rescue Object => e
rollback!
raise
ensure
- @rollback_requests = nil
+ self.rollback_requests = nil if Thread.main == Thread.current
end
end
@@ -99,6 +107,9 @@ def find_and_execute_task(path, hooks={})
protected
def rollback!
+ return if Thread.current[:rollback_requests].nil?
+ Thread.current[:rolled_back] = true
+
# throw the task back on the stack so that roles are properly
# interpreted in the scope of the task in question.
rollback_requests.reverse.each do |frame|
Please sign in to comment.
Something went wrong with that request. Please try again.