sshkit 1.8.1 → 1.9.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
[![
|
7
|
-
[![
|
6
|
+
[![Gem Version](https://badge.fury.io/rb/sshkit.svg)](https://rubygems.org/gems/sshkit)
|
7
|
+
[![Build Status](https://travis-ci.org/capistrano/sshkit.svg?branch=master)](https://travis-ci.org/capistrano/sshkit)
|
8
|
+
[![Dependency Status](https://gemnasium.com/capistrano/sshkit.svg)](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"
|