sshkit 1.8.1 → 1.9.0.rc1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +4 -3
- data/CHANGELOG.md +39 -0
- data/CONTRIBUTING.md +10 -0
- data/EXAMPLES.md +3 -1
- data/README.md +9 -10
- data/Rakefile +7 -1
- data/lib/sshkit/all.rb +2 -1
- data/lib/sshkit/backends/abstract.rb +25 -1
- data/lib/sshkit/backends/connection_pool.rb +139 -100
- data/lib/sshkit/backends/connection_pool/cache.rb +67 -0
- data/lib/sshkit/backends/connection_pool/nil_cache.rb +11 -0
- data/lib/sshkit/backends/netssh.rb +5 -9
- data/lib/sshkit/backends/printer.rb +5 -0
- data/lib/sshkit/command.rb +5 -1
- data/lib/sshkit/command_map.rb +0 -2
- data/lib/sshkit/configuration.rb +6 -2
- data/lib/sshkit/coordinator.rb +7 -7
- data/lib/sshkit/dsl.rb +0 -2
- data/lib/sshkit/formatters/abstract.rb +3 -2
- data/lib/sshkit/formatters/pretty.rb +3 -2
- data/lib/sshkit/mapping_interaction_handler.rb +4 -3
- data/lib/sshkit/runners/parallel.rb +3 -4
- data/lib/sshkit/version.rb +1 -1
- data/sshkit.gemspec +3 -2
- data/test/functional/backends/test_local.rb +1 -1
- data/test/helper.rb +5 -8
- data/test/unit/backends/test_abstract.rb +36 -0
- data/test/unit/backends/test_connection_pool.rb +48 -49
- data/test/unit/backends/test_printer.rb +5 -5
- data/test/unit/formatters/test_custom.rb +8 -2
- data/test/unit/test_command_map.rb +9 -0
- data/test/unit/test_configuration.rb +6 -0
- data/test/unit/test_coordinator.rb +27 -1
- data/test/unit/test_dsl.rb +26 -0
- data/test/unit/test_host.rb +6 -2
- metadata +43 -31
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: abfe247587ee2e726dbc24ea5de49ac889398eeb
|
4
|
+
data.tar.gz: 68b375157b3a48703d6f7cc7ae46888a4f41e1b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1ebb765665fa9b9d82277a9346e1a94a3e65cf818095976d970d8a928c692eaf2214c4fc39b5781c0b9ada96d6743cda52010aa91dc4b71a05953d890b34729a
|
7
|
+
data.tar.gz: d0c45809d3ad62dd5c3639c3a435c9d8b796757ff6b8cd58a802c82b15493fd1c8320ec72c551c1179e2b2fb5e7ac83acce2bbf97fb5968788a7e135331abb32
|
data/.travis.yml
CHANGED
data/CHANGELOG.md
CHANGED
@@ -8,6 +8,44 @@ appear at the top.
|
|
8
8
|
* Add your entries below here, remember to credit yourself however you want
|
9
9
|
to be credited!
|
10
10
|
|
11
|
+
## 1.9.0.rc1
|
12
|
+
|
13
|
+
### Potentially breaking changes
|
14
|
+
|
15
|
+
* The SSHKit DSL is no longer automatically included when you `require` it.
|
16
|
+
**This means you must now explicitly `include SSHKit::DSL`.**
|
17
|
+
See [PR #219](https://github.com/capistrano/sshkit/pull/219) for details.
|
18
|
+
@beatrichartz
|
19
|
+
* `SSHKit::Backend::Printer#test` now always returns true
|
20
|
+
[PR #312](https://github.com/capistrano/sshkit/pull/312) @mikz
|
21
|
+
|
22
|
+
### New features
|
23
|
+
|
24
|
+
* `SSHKit::Formatter::Abstract` now accepts an optional Hash of options
|
25
|
+
[PR #308](https://github.com/capistrano/sshkit/pull/308) @mattbrictson
|
26
|
+
* Add `SSHKit::Backend.current` so that Capistrano plugin authors can refactor
|
27
|
+
helper methods and still have easy access to the currently-executing Backend
|
28
|
+
without having to use global variables.
|
29
|
+
* Add `SSHKit.config.default_runner` options that allows to override default command runner.
|
30
|
+
This option also accepts a name of the custom runner class.
|
31
|
+
* The ConnectionPool has been rewritten in this release to be more efficient
|
32
|
+
and have a cleaner internal API. You can still completely disable the pool
|
33
|
+
by setting `SSHKit::Backend::Netssh.pool.idle_timeout = 0`.
|
34
|
+
@mattbrictson @byroot [PR #328](https://github.com/capistrano/sshkit/pull/328)
|
35
|
+
|
36
|
+
### Bug fixes
|
37
|
+
|
38
|
+
* make sure working directory for commands is properly cleared after `within` blocks
|
39
|
+
[PR #307](https://github.com/capistrano/sshkit/pull/307)
|
40
|
+
@steved
|
41
|
+
* display more accurate string for commands with spaces being output in `Formatter::Pretty`
|
42
|
+
[PR #304](https://github.com/capistrano/sshkit/pull/304)
|
43
|
+
@steved
|
44
|
+
[PR #319](https://github.com/capistrano/sshkit/pull/319) @mattbrictson
|
45
|
+
* Fix a race condition experienced in JRuby that could cause multi-server
|
46
|
+
deploys to fail. [PR #322](https://github.com/capistrano/sshkit/pull/322)
|
47
|
+
@mattbrictson
|
48
|
+
|
11
49
|
## 1.8.1
|
12
50
|
|
13
51
|
* Change license to MIT, thanks to all the patient contributors who gave
|
@@ -86,6 +124,7 @@ appear at the top.
|
|
86
124
|
* Removed dependency on the `colorize` gem. SSHKit now implements its own ANSI color logic, with no external dependencies. Note that SSHKit now only supports the `:bold` or plain modes. Other modes will be gracefully ignored. [#263](https://github.com/capistrano/sshkit/issues/263)
|
87
125
|
* New API for setting the formatter: `use_format`. This differs from `format=` in that it accepts options or arguments that will be passed to the formatter's constructor. The `format=` syntax will be deprecated in a future release. [#295](https://github.com/capistrano/sshkit/issues/295)
|
88
126
|
* SSHKit now immediately raises a `NameError` if you try to set a formatter that does not exist. [#295](https://github.com/capistrano/sshkit/issues/295)
|
127
|
+
* Fix error message when the formatter does not exist. [#301](https://github.com/capistrano/sshkit/pull/301)
|
89
128
|
|
90
129
|
## 1.7.1
|
91
130
|
|
data/CONTRIBUTING.md
CHANGED
@@ -28,6 +28,16 @@ ruby versions.
|
|
28
28
|
**The Travis build does not run the functional tests,
|
29
29
|
so make sure all the tests pass locally before creating your PR.**
|
30
30
|
|
31
|
+
## Coding guidelines
|
32
|
+
|
33
|
+
This project uses [RuboCop](https://github.com/bbatsov/rubocop) to enforce standard Ruby coding
|
34
|
+
guidelines. Currently we run RuboCop's lint rules only, which check for readability issues
|
35
|
+
like indentation, ambiguity, and useless/unreachable code.
|
36
|
+
|
37
|
+
* Test that your contributions pass with `rake lint`
|
38
|
+
* The linter is also run as part of the full test suite with `rake`
|
39
|
+
* Note the Travis build will fail and your PR cannot be merged if the linter finds errors
|
40
|
+
|
31
41
|
## Changelog
|
32
42
|
|
33
43
|
Most changes should have an accompanying entry in the [CHANGELOG](CHANGELOG.md), unless they
|
data/EXAMPLES.md
CHANGED
@@ -366,12 +366,14 @@ known test cases, it works. The key thing is that `if` is not mapped to
|
|
366
366
|
Into the `Rakefile` simply put something like:
|
367
367
|
|
368
368
|
```ruby
|
369
|
-
require 'sshkit
|
369
|
+
require 'sshkit'
|
370
370
|
|
371
371
|
SSHKit.config.command_map[:rake] = "./bin/rake"
|
372
372
|
|
373
373
|
desc "Deploy the site, pulls from Git, migrate the db and precompile assets, then restart Passenger."
|
374
374
|
task :deploy do
|
375
|
+
include SSHKit::DSL
|
376
|
+
|
375
377
|
on "example.com" do |host|
|
376
378
|
within "/opt/sites/example.com" do
|
377
379
|
execute :git, :pull
|
data/README.md
CHANGED
@@ -3,8 +3,9 @@
|
|
3
3
|
**SSHKit** is a toolkit for running commands in a structured way on one or
|
4
4
|
more servers.
|
5
5
|
|
6
|
-
[](https://rubygems.org/gems/sshkit)
|
7
|
+
[](https://travis-ci.org/capistrano/sshkit)
|
8
|
+
[](https://gemnasium.com/capistrano/sshkit)
|
8
9
|
|
9
10
|
## How might it work?
|
10
11
|
|
@@ -12,7 +13,7 @@ The typical use-case looks something like this:
|
|
12
13
|
|
13
14
|
```ruby
|
14
15
|
require 'sshkit'
|
15
|
-
|
16
|
+
include SSHKit::DSL
|
16
17
|
|
17
18
|
on %w{1.example.com 2.example.com}, in: :sequence, wait: 5 do |host|
|
18
19
|
within "/opt/sites/example.com" do
|
@@ -65,7 +66,7 @@ you can pass the `strip: false` option: `capture(:ls, '-l', strip: false)`
|
|
65
66
|
#### Transferring files
|
66
67
|
|
67
68
|
All backends also support the `upload!` and `download!` methods for transferring files.
|
68
|
-
For the remote
|
69
|
+
For the remote backend, the file is tranferred with scp.
|
69
70
|
|
70
71
|
```ruby
|
71
72
|
on '1.example.com' do
|
@@ -442,24 +443,22 @@ ENV['SSHKIT_COLOR'] = 'TRUE'
|
|
442
443
|
|
443
444
|
Want custom output formatting? Here's what you have to do:
|
444
445
|
|
445
|
-
1. Write a new formatter class in the `SSHKit::Formatter` module.
|
446
|
+
1. Write a new formatter class in the `SSHKit::Formatter` module. Your class should subclass `SSHKit::Formatter::Abstract` to inherit conveniences and common behavior. For a basic an example, check out the [Pretty](https://github.com/capistrano/sshkit/blob/master/lib/sshkit/formatters/pretty.rb) formatter.
|
446
447
|
1. Set the output format as described above. E.g. if your new formatter is called `FooBar`:
|
447
448
|
|
448
449
|
```ruby
|
449
450
|
SSHKit.config.use_format :foobar
|
450
451
|
```
|
451
452
|
|
452
|
-
|
453
|
+
All formatters that extend from `SSHKit::Formatter::Abstract` accept an options Hash as a constructor argument. You can pass options to your formatter like this:
|
453
454
|
|
454
455
|
```ruby
|
455
456
|
SSHKit.config.use_format :foobar, :my_option => "value"
|
456
457
|
```
|
457
458
|
|
458
|
-
|
459
|
+
You can then access these options using the `options` accessor within your formatter code.
|
459
460
|
|
460
|
-
|
461
|
-
SSHKit::Formatter::FooBar.new($stdout, :my_option => "value")
|
462
|
-
```
|
461
|
+
For a much more full-featured formatter example that makes use of options, check out the [Airbrussh repository](https://github.com/mattbrictson/airbrussh/).
|
463
462
|
|
464
463
|
## Output Verbosity
|
465
464
|
|
data/Rakefile
CHANGED
@@ -2,8 +2,9 @@
|
|
2
2
|
|
3
3
|
require 'bundler/gem_tasks'
|
4
4
|
require 'rake/testtask'
|
5
|
+
require 'rubocop/rake_task'
|
5
6
|
|
6
|
-
task :default => :test
|
7
|
+
task :default => [:test, :lint]
|
7
8
|
|
8
9
|
desc "Run all tests"
|
9
10
|
task :test => ['test:units', 'test:functional']
|
@@ -26,6 +27,11 @@ Rake::Task["test:functional"].enhance do
|
|
26
27
|
warn "Remember there are still some VMs running, kill them with `vagrant halt` if you are finished using them."
|
27
28
|
end
|
28
29
|
|
30
|
+
desc 'Run RuboCop lint checks'
|
31
|
+
RuboCop::RakeTask.new(:lint) do |task|
|
32
|
+
task.options = ['--lint']
|
33
|
+
end
|
34
|
+
|
29
35
|
task "release:rubygem_push" do
|
30
36
|
# Delay loading Chandler until this point, since it requires Ruby >= 2.1,
|
31
37
|
# which may not be available in all environments (e.g. Travis).
|
data/lib/sshkit/all.rb
CHANGED
@@ -10,6 +10,7 @@ require_relative 'configuration'
|
|
10
10
|
require_relative 'coordinator'
|
11
11
|
|
12
12
|
require_relative 'deprecation_logger'
|
13
|
+
require_relative 'dsl'
|
13
14
|
|
14
15
|
require_relative 'exception'
|
15
16
|
|
@@ -35,4 +36,4 @@ require_relative 'backends/connection_pool'
|
|
35
36
|
require_relative 'backends/printer'
|
36
37
|
require_relative 'backends/netssh'
|
37
38
|
require_relative 'backends/local'
|
38
|
-
require_relative 'backends/skipper'
|
39
|
+
require_relative 'backends/skipper'
|
@@ -4,6 +4,19 @@ module SSHKit
|
|
4
4
|
|
5
5
|
MethodUnavailableError = Class.new(SSHKit::StandardError)
|
6
6
|
|
7
|
+
# The Backend instance that is running in the current thread. If no Backend
|
8
|
+
# is running, returns `nil` instead.
|
9
|
+
#
|
10
|
+
# Example:
|
11
|
+
#
|
12
|
+
# on(:local) do
|
13
|
+
# self == SSHKit::Backend.current # => true
|
14
|
+
# end
|
15
|
+
#
|
16
|
+
def self.current
|
17
|
+
Thread.current["sshkit_backend"]
|
18
|
+
end
|
19
|
+
|
7
20
|
class Abstract
|
8
21
|
|
9
22
|
extend Forwardable
|
@@ -12,7 +25,10 @@ module SSHKit
|
|
12
25
|
attr_reader :host
|
13
26
|
|
14
27
|
def run
|
28
|
+
Thread.current["sshkit_backend"] = self
|
15
29
|
instance_exec(@host, &@block)
|
30
|
+
ensure
|
31
|
+
Thread.current["sshkit_backend"] = nil
|
16
32
|
end
|
17
33
|
|
18
34
|
def initialize(host, &block)
|
@@ -121,8 +137,16 @@ module SSHKit
|
|
121
137
|
command(args, options).tap { |cmd| execute_command(cmd) }
|
122
138
|
end
|
123
139
|
|
140
|
+
def pwd_path
|
141
|
+
if @pwd.nil? || @pwd.empty?
|
142
|
+
nil
|
143
|
+
else
|
144
|
+
File.join(@pwd)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
124
148
|
def command(args, options)
|
125
|
-
SSHKit::Command.new(*[*args, options.merge({in:
|
149
|
+
SSHKit::Command.new(*[*args, options.merge({in: pwd_path, env: @env, host: @host, user: @user, group: @group})])
|
126
150
|
end
|
127
151
|
|
128
152
|
end
|
@@ -1,120 +1,159 @@
|
|
1
|
+
require "monitor"
|
1
2
|
require "thread"
|
2
3
|
|
3
|
-
# Since we call to_s on
|
4
|
-
#
|
5
|
-
# Otherwise identical objects with different memory address won't
|
6
|
-
#
|
7
|
-
#
|
8
|
-
#
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
4
|
+
# Since we call to_s on new connection arguments and use that as a cache key, we
|
5
|
+
# need to make sure the memory address of the object is not used as part of the
|
6
|
+
# key. Otherwise identical objects with different memory address won't reuse the
|
7
|
+
# cache.
|
8
|
+
#
|
9
|
+
# In the case of proxy commands, this can lead to proxy processes leaking, and
|
10
|
+
# in severe cases can cause deploys to fail due to default file descriptor
|
11
|
+
# limits. An alternate solution would be to use a different means of generating
|
12
|
+
# hash keys.
|
13
|
+
#
|
14
|
+
require "net/ssh/proxy/command"
|
15
|
+
class Net::SSH::Proxy::Command
|
16
|
+
# Ensure a stable string value is used, rather than memory address.
|
17
|
+
def inspect
|
18
|
+
@command_line_template
|
14
19
|
end
|
15
|
-
end
|
16
|
-
|
17
|
-
module SSHKit
|
18
|
-
|
19
|
-
module Backend
|
20
|
-
|
21
|
-
class ConnectionPool
|
20
|
+
end
|
22
21
|
|
23
|
-
|
22
|
+
# The ConnectionPool caches connections and allows them to be reused, so long as
|
23
|
+
# the reuse happens within the `idle_timeout` period. Timed out connections are
|
24
|
+
# closed, forcing a new connection to be used in that case.
|
25
|
+
#
|
26
|
+
# Additionally, a background thread is started to check for abandoned
|
27
|
+
# connections that have timed out without any attempt at being reused. These
|
28
|
+
# are eventually closed as well and removed from the cache.
|
29
|
+
#
|
30
|
+
# If `idle_timeout` set to `false`, `0`, or `nil`, no caching is performed, and
|
31
|
+
# a new connection is created and then immediately closed each time. The default
|
32
|
+
# timeout is 30 (seconds).
|
33
|
+
#
|
34
|
+
# There is a single public method: `with`. Example usage:
|
35
|
+
#
|
36
|
+
# pool = SSHKit::Backend::ConnectionPool.new
|
37
|
+
# pool.with(Net::SSH.method(:start), "host", "username") do |connection|
|
38
|
+
# # do stuff with connection
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
class SSHKit::Backend::ConnectionPool
|
42
|
+
attr_accessor :idle_timeout
|
43
|
+
|
44
|
+
def initialize(idle_timeout=30)
|
45
|
+
@idle_timeout = idle_timeout
|
46
|
+
@caches = {}
|
47
|
+
@caches.extend(MonitorMixin)
|
48
|
+
@timed_out_connections = Queue.new
|
49
|
+
Thread.new { run_eviction_loop }
|
50
|
+
end
|
24
51
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
52
|
+
# Creates a new connection or reuses a cached connection (if possible) and
|
53
|
+
# yields the connection to the given block. Connections are created by
|
54
|
+
# invoking the `connection_factory` proc with the given `args`. The arguments
|
55
|
+
# are used to construct a key used for caching.
|
56
|
+
def with(connection_factory, *args)
|
57
|
+
cache = find_cache(args)
|
58
|
+
conn = cache.pop || begin
|
59
|
+
connection_factory.call(*args)
|
60
|
+
end
|
61
|
+
yield(conn)
|
62
|
+
ensure
|
63
|
+
cache.push(conn) unless conn.nil?
|
64
|
+
end
|
30
65
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
entry = find_live_entry(key)
|
37
|
-
end
|
38
|
-
entry || create_new_entry(new_connection_args, key, &block)
|
39
|
-
end
|
66
|
+
# Immediately remove all cached connections, without closing them. This only
|
67
|
+
# exists for unit test purposes.
|
68
|
+
def flush_connections
|
69
|
+
caches.synchronize { caches.clear }
|
70
|
+
end
|
40
71
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
50
|
-
end
|
72
|
+
# Immediately close all cached connections and empty the pool.
|
73
|
+
def close_connections
|
74
|
+
caches.synchronize do
|
75
|
+
caches.values.each(&:clear)
|
76
|
+
caches.clear
|
77
|
+
process_deferred_close
|
78
|
+
end
|
79
|
+
end
|
51
80
|
|
52
|
-
|
53
|
-
@mutex.synchronize do
|
54
|
-
@pool.values.flatten.map(&:connection).uniq.each do |conn|
|
55
|
-
if conn.respond_to?(:closed?) && conn.respond_to?(:close)
|
56
|
-
conn.close unless conn.closed?
|
57
|
-
end
|
58
|
-
end
|
59
|
-
@pool.clear
|
60
|
-
end
|
61
|
-
end
|
81
|
+
private
|
62
82
|
|
63
|
-
|
64
|
-
@mutex.synchronize { @pool.clear }
|
65
|
-
end
|
83
|
+
attr_reader :caches, :timed_out_connections
|
66
84
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
@mutex.synchronize do
|
71
|
-
@pool.each_value do |entries|
|
72
|
-
entries.collect! do |entry|
|
73
|
-
if entry.expired?
|
74
|
-
entry.close unless entry.closed?
|
75
|
-
nil
|
76
|
-
else
|
77
|
-
entry
|
78
|
-
end
|
79
|
-
end.compact!
|
80
|
-
end
|
81
|
-
end
|
82
|
-
end
|
85
|
+
def cache_enabled?
|
86
|
+
idle_timeout && idle_timeout > 0
|
87
|
+
end
|
83
88
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
89
|
+
# Look up a Cache that matches the given connection arguments.
|
90
|
+
def find_cache(args)
|
91
|
+
if cache_enabled?
|
92
|
+
key = args.to_s
|
93
|
+
caches[key] || thread_safe_find_or_create_cache(key)
|
94
|
+
else
|
95
|
+
NilCache.new(method(:silently_close_connection))
|
96
|
+
end
|
97
|
+
end
|
93
98
|
|
94
|
-
|
95
|
-
|
99
|
+
# Cache creation needs to happen in a mutex, because otherwise a race
|
100
|
+
# condition might cause two identical caches to be created for the same key.
|
101
|
+
def thread_safe_find_or_create_cache(key)
|
102
|
+
caches.synchronize do
|
103
|
+
caches[key] ||= begin
|
104
|
+
Cache.new(idle_timeout, method(:silently_close_connection_later))
|
96
105
|
end
|
106
|
+
end
|
107
|
+
end
|
97
108
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
end
|
109
|
+
# Loops indefinitely to close connections and to find abandoned connections
|
110
|
+
# that need to be closed.
|
111
|
+
def run_eviction_loop
|
112
|
+
loop do
|
113
|
+
process_deferred_close
|
104
114
|
|
105
|
-
|
106
|
-
|
107
|
-
|
115
|
+
# Periodically sweep all Caches to evict stale connections
|
116
|
+
sleep([idle_timeout, 5].min)
|
117
|
+
caches.values.each(&:evict)
|
118
|
+
end
|
119
|
+
end
|
108
120
|
|
109
|
-
|
110
|
-
|
111
|
-
|
121
|
+
# Immediately close any connections that are pending closure.
|
122
|
+
# rubocop:disable Lint/HandleExceptions
|
123
|
+
def process_deferred_close
|
124
|
+
until timed_out_connections.empty?
|
125
|
+
connection = timed_out_connections.pop(true)
|
126
|
+
silently_close_connection(connection)
|
127
|
+
end
|
128
|
+
rescue ThreadError
|
129
|
+
# Queue#pop(true) raises ThreadError if the queue is empty.
|
130
|
+
# This could only happen if `close_connections` is called at the same time
|
131
|
+
# the background eviction thread has woken up to close connections. In any
|
132
|
+
# case, it is not something we need to care about, since an empty queue is
|
133
|
+
# perfectly OK.
|
134
|
+
end
|
135
|
+
# rubocop:enable Lint/HandleExceptions
|
112
136
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
137
|
+
# Adds the connection to a queue that is processed asynchronously by a
|
138
|
+
# background thread. The connection will eventually be closed.
|
139
|
+
def silently_close_connection_later(connection)
|
140
|
+
timed_out_connections << connection
|
141
|
+
end
|
117
142
|
|
118
|
-
|
143
|
+
# Close the given `connection` immediately, assuming it responds to a `close`
|
144
|
+
# method. If it doesn't, or if `nil` is provided, it is silently ignored. Any
|
145
|
+
# `StandardError` is also silently ignored. Returns `true` if the connection
|
146
|
+
# was closed; `false` if it was already closed or could not be closed due to
|
147
|
+
# an error.
|
148
|
+
def silently_close_connection(connection)
|
149
|
+
return false unless connection.respond_to?(:close)
|
150
|
+
return false if connection.respond_to?(:closed?) && connection.closed?
|
151
|
+
connection.close
|
152
|
+
true
|
153
|
+
rescue StandardError
|
154
|
+
false
|
119
155
|
end
|
120
156
|
end
|
157
|
+
|
158
|
+
require "sshkit/backends/connection_pool/cache"
|
159
|
+
require "sshkit/backends/connection_pool/nil_cache"
|