waitutil 0.1.0 → 0.2.0
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 +5 -13
- data/.gitignore +2 -0
- data/.travis.yml +2 -1
- data/README.md +49 -4
- data/VERSION +1 -1
- data/lib/waitutil.rb +71 -8
- data/spec/waitutil_spec.rb +45 -3
- data/waitutil.gemspec +1 -1
- metadata +29 -31
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
ZTc0Y2RlYTM5MjZmZjI2YjIxMmYzNDZmY2U4OGJmYzljOTljNzljZQ==
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0f139cee6a8804a8beddc4adb4adfe9cf1c2e8d8
|
4
|
+
data.tar.gz: ef6a331a094e72d2b7b877a75d1cd38ff6962c1e
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
MjU2YjNmZWRlMjFjZGIxY2Y5YWRmMDhlZDQyY2ZmNmU1MDJlZmQxNDRkMDBk
|
11
|
-
N2IyM2Y0N2JiNmYyYTBjYmNmNGUzYmJlZDY5OGEyNmE0ZTA5ZWE=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
NDM4N2Q3YTMxZGEwNmIwMzdlZDViYWZkOWQ3ODM3ODk2NDM1ODIwNjRkYzRh
|
14
|
-
NmFkMjIxODkyODQwNDlkOTYxNDgwZmI1MmM3YThhYjdhN2M3NzhhYTIxNDAw
|
15
|
-
NjYyYjkzOGUyOWFkMWU2NmViMjI4ODQ2MjcyODc5ZGJmOGMyMzE=
|
6
|
+
metadata.gz: 2af4abd0f7f6f8b115cf6dd6058bb93496dbd686eba63530106d84c9a571420709339220c9e2857dca00f4af4b2a111b59ece159a4288ea46cd98cfcfd23ee9b
|
7
|
+
data.tar.gz: 2e437fd465f552294ad4698359d58e24c15d2970215a7e24224acd7f4512684cd7578654d1658ac909bc85ae65c941fc9a2d2efbdc67da317576dcf3324e68c3
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -1,33 +1,78 @@
|
|
1
1
|
## waitutil
|
2
2
|
|
3
|
-
[](https://travis-ci.org/rubytools/waitutil)
|
4
4
|
|
5
5
|
`waitutil` provides tools for waiting for various conditions to occur, with a configurable
|
6
6
|
delay time, timeout, and logging.
|
7
7
|
|
8
|
+
GitHub: https://github.com/rubytools/waitutil
|
9
|
+
|
10
|
+
RubyGems: http://rubygems.org/gems/waitutil
|
11
|
+
|
12
|
+
Documentation: http://rubytools.github.io/waitutil/
|
13
|
+
|
8
14
|
### Examples
|
9
15
|
|
16
|
+
Wait methods take a block that returns `true` or `false`.
|
17
|
+
|
10
18
|
#### Waiting for conditions
|
11
19
|
|
12
20
|
Maximum wait time is one minute by default, and the delay time is one second.
|
21
|
+
|
13
22
|
```ruby
|
14
23
|
WaitUtil.wait_for_condition("my_event to happen") do
|
15
24
|
check_if_my_event_happened
|
16
25
|
end
|
17
26
|
```
|
18
27
|
|
19
|
-
Customized wait time and delay time
|
28
|
+
##### Customized wait time and delay time
|
29
|
+
|
20
30
|
```ruby
|
21
31
|
WaitUtil.wait_for_condition("my_event to happen", :timeout_sec => 30, :delay_sec => 0.5) do
|
22
32
|
check_if_my_event_happened
|
23
33
|
end
|
24
34
|
```
|
25
35
|
|
36
|
+
##### Verbose logging
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
WaitUtil.wait_for_condition('my event', :verbose => true) { sleep(1) }
|
40
|
+
```
|
41
|
+
|
42
|
+
Output:
|
43
|
+
|
44
|
+
```
|
45
|
+
I, [2014-02-16T00:34:31.511915 #15897] INFO -- : Waiting for my event for up to 60 seconds
|
46
|
+
I, [2014-02-16T00:34:32.512223 #15897] INFO -- : Success waiting for my event (1.000153273 seconds)
|
47
|
+
```
|
48
|
+
|
49
|
+
##### Returning additional information for the timeout log message
|
50
|
+
|
51
|
+
```ruby
|
52
|
+
attempt = 1
|
53
|
+
WaitUtil.wait_for_condition('my event', :verbose => true, :timeout_sec => 3, :delay_sec => 1) do
|
54
|
+
sleep(1)
|
55
|
+
attempt += 1
|
56
|
+
[false, "attempt #{attempt}"] # the second element goes into the log message
|
57
|
+
end
|
58
|
+
```
|
59
|
+
|
60
|
+
Output:
|
61
|
+
|
62
|
+
```
|
63
|
+
I, [2014-02-16T00:46:53.647936 #17252] INFO -- : Waiting for my event for up to 3 seconds
|
64
|
+
WaitUtil::TimeoutError: Timed out waiting for my event (3 seconds elapsed): attempt 3
|
65
|
+
from /home/mbautin/.rvm/gems/ruby-2.1.0/gems/waitutil-0.1.0/lib/waitutil.rb:39:in `wait_for_condition'
|
66
|
+
from (irb):9
|
67
|
+
from /home/mbautin/.rvm/rubies/ruby-2.1.0/bin/irb:11:in `<main>'
|
68
|
+
```
|
69
|
+
|
26
70
|
#### Waiting for service availability
|
27
71
|
|
28
|
-
Wait for a TCP server to be available:
|
72
|
+
Wait for a TCP server to be available using [wait_for_service](http://rubytools.github.io/waitutil/WaitUtil.html#wait_for_service-instance_method):
|
73
|
+
|
29
74
|
```ruby
|
30
|
-
WaitUtil.wait_for_service('example.com',
|
75
|
+
WaitUtil.wait_for_service('my service', 'example.com', 80)
|
31
76
|
```
|
32
77
|
|
33
78
|
### License
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
data/lib/waitutil.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'logger'
|
2
|
+
require 'socket'
|
2
3
|
|
3
4
|
module WaitUtil
|
4
5
|
|
@@ -33,32 +34,43 @@ module WaitUtil
|
|
33
34
|
end
|
34
35
|
|
35
36
|
start_time = Time.now
|
37
|
+
stop_time = start_time + timeout_sec
|
36
38
|
iteration = 0
|
39
|
+
|
40
|
+
# Time when we started to evaluate the condition.
|
41
|
+
condition_eval_start_time = start_time
|
42
|
+
|
37
43
|
until is_condition_met(condition_result = yield(iteration))
|
38
|
-
|
44
|
+
current_time = Time.now
|
45
|
+
if current_time - start_time >= timeout_sec
|
39
46
|
raise TimeoutError.new(
|
40
47
|
"Timed out waiting for #{description} (#{timeout_sec} seconds elapsed)" +
|
41
48
|
get_additional_message(condition_result)
|
42
49
|
)
|
43
50
|
end
|
44
|
-
|
51
|
+
|
52
|
+
# The condition evaluation function might have taken some time, so we subtract that time
|
53
|
+
# from the time we have to wait.
|
54
|
+
sleep_time_sec = condition_eval_start_time + delay_sec - current_time
|
55
|
+
sleep(sleep_time_sec) if sleep_time_sec > 0
|
56
|
+
|
45
57
|
iteration += 1
|
58
|
+
condition_eval_start_time = Time.now # we will evaluate the condition again immediately
|
46
59
|
end
|
60
|
+
|
47
61
|
if verbose
|
48
62
|
@@logger.info("Success waiting for #{description} (#{Time.now - start_time} seconds)")
|
49
63
|
end
|
50
64
|
true
|
51
65
|
end
|
52
66
|
|
53
|
-
# Wait until a service is available at the given host/port.
|
67
|
+
# Wait until a TCP service is available at the given host/port.
|
54
68
|
def wait_for_service(description, host, port, options = {})
|
55
|
-
wait_for_condition("#{description}
|
69
|
+
wait_for_condition("#{description} to become available on #{host}, port #{port}",
|
56
70
|
options) do
|
57
71
|
begin
|
58
|
-
|
59
|
-
|
60
|
-
true
|
61
|
-
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
|
72
|
+
is_tcp_port_open(host, port, options[:delay_sec] || DEFAULT_DELAY_SEC)
|
73
|
+
rescue SocketError
|
62
74
|
false
|
63
75
|
end
|
64
76
|
end
|
@@ -74,5 +86,56 @@ module WaitUtil
|
|
74
86
|
condition_result.kind_of?(Array) ? ': ' + condition_result[1] : ''
|
75
87
|
end
|
76
88
|
|
89
|
+
# Check if the given TCP port is open on the given port with a timeout.
|
90
|
+
def is_tcp_port_open(host, port, timeout_sec = nil)
|
91
|
+
if RUBY_PLATFORM == 'java'
|
92
|
+
# Unfortunately, our select-based approach does not work on JRuby.
|
93
|
+
begin
|
94
|
+
s = TCPSocket.new(host, port)
|
95
|
+
s.close
|
96
|
+
true
|
97
|
+
rescue Errno::ECONNREFUSED, Errno::EHOSTUNREACH
|
98
|
+
false
|
99
|
+
end
|
100
|
+
else
|
101
|
+
addr_info = begin
|
102
|
+
Socket.getaddrinfo(host, port)
|
103
|
+
rescue SocketError
|
104
|
+
return false
|
105
|
+
end.select {|item| item[0] == 'AF_INET' }
|
106
|
+
|
107
|
+
return false if addr_info.empty?
|
108
|
+
|
109
|
+
socket = Socket.new(Socket::AF_INET, Socket::SOCK_STREAM, 0)
|
110
|
+
ip_addr = addr_info[0][3]
|
111
|
+
sockaddr = Socket.sockaddr_in(port, ip_addr)
|
112
|
+
result = begin
|
113
|
+
begin
|
114
|
+
socket.connect_nonblock(sockaddr)
|
115
|
+
true
|
116
|
+
rescue Errno::EAFNOSUPPORT
|
117
|
+
@@logger.error("Address family not supported for #{ip_addr}")
|
118
|
+
false
|
119
|
+
end
|
120
|
+
rescue Errno::EINPROGRESS
|
121
|
+
reader, writer, error = IO.select([socket], [socket], [socket], timeout_sec)
|
122
|
+
if writer.nil? || writer.empty?
|
123
|
+
false
|
124
|
+
else
|
125
|
+
# Sometimes we have to write some data to the socket to find out whether we are really
|
126
|
+
# connected.
|
127
|
+
begin
|
128
|
+
writer[0].write_nonblock("\x0")
|
129
|
+
true
|
130
|
+
rescue Errno::ECONNREFUSED
|
131
|
+
false
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
socket.close
|
136
|
+
result
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
77
140
|
extend WaitUtil
|
78
141
|
end
|
data/spec/waitutil_spec.rb
CHANGED
@@ -83,13 +83,55 @@ describe WaitUtil do
|
|
83
83
|
describe '.wait_for_service' do
|
84
84
|
BIND_IP = '127.0.0.1'
|
85
85
|
|
86
|
+
it 'waits for service availability' do
|
87
|
+
WaitUtil.wait_for_service('Google', 'google.com', 80, :timeout_sec => 0.5)
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'times out when host name does not exist' do
|
91
|
+
begin
|
92
|
+
WaitUtil.wait_for_service(
|
93
|
+
'non-existent service',
|
94
|
+
'nosuchhost_waitutil_ruby_module.com',
|
95
|
+
12345,
|
96
|
+
:timeout_sec => 0.2,
|
97
|
+
:delay_sec => 0.1
|
98
|
+
)
|
99
|
+
fail("Expecting WaitUtil::TimeoutError but nothing was raised")
|
100
|
+
rescue WaitUtil::TimeoutError => ex
|
101
|
+
expect(ex.to_s.gsub(/ \(.*/, '')).to eq(
|
102
|
+
'Timed out waiting for non-existent service to become available on ' \
|
103
|
+
'nosuchhost_waitutil_ruby_module.com, port 12345'
|
104
|
+
)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
if RUBY_PLATFORM != 'java'
|
109
|
+
# Our current implementation will get stuck on this if running JRuby.
|
110
|
+
it 'times out when port is closed' do
|
111
|
+
begin
|
112
|
+
WaitUtil.wait_for_service(
|
113
|
+
'wrong port on Google',
|
114
|
+
'google.com',
|
115
|
+
12345,
|
116
|
+
:timeout_sec => 0.2,
|
117
|
+
:delay_sec => 0.1
|
118
|
+
)
|
119
|
+
rescue WaitUtil::TimeoutError => ex
|
120
|
+
expect(ex.to_s.gsub(/ \(.*/, '')).to eq(
|
121
|
+
'Timed out waiting for wrong port on Google to become available on google.com, ' \
|
122
|
+
'port 12345'
|
123
|
+
)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
86
128
|
it 'should succeed immediately when there is a TCP server listening' do
|
87
129
|
# Find an unused port.
|
88
130
|
socket = Socket.new(:INET, :STREAM, 0)
|
89
131
|
sockaddr = if RUBY_ENGINE == 'jruby'
|
90
|
-
ServerSocket.pack_sockaddr_in(
|
132
|
+
ServerSocket.pack_sockaddr_in(0, "127.0.0.1")
|
91
133
|
else
|
92
|
-
|
134
|
+
Socket.pack_sockaddr_in(0, "127.0.0.1")
|
93
135
|
end
|
94
136
|
socket.bind(sockaddr)
|
95
137
|
port = socket.local_address.ip_port
|
@@ -130,6 +172,6 @@ describe WaitUtil do
|
|
130
172
|
)
|
131
173
|
}.to raise_error(WaitUtil::TimeoutError)
|
132
174
|
end
|
133
|
-
|
134
175
|
end
|
176
|
+
|
135
177
|
end
|
data/waitutil.gemspec
CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |gem|
|
|
8
8
|
gem.email = ['mbautin@gmail.com']
|
9
9
|
gem.description = 'Utilities for waiting for various conditions'
|
10
10
|
gem.summary = 'Utilities for waiting for various conditions'
|
11
|
-
gem.homepage = "http://github.com/
|
11
|
+
gem.homepage = "http://github.com/rubytools/#{GEM_NAME}"
|
12
12
|
|
13
13
|
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
14
14
|
gem.files = `git ls-files`.split("\n").map(&:strip)
|
metadata
CHANGED
@@ -1,71 +1,71 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: waitutil
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mikhail Bautin
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-03-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
15
|
-
|
15
|
+
version_requirements: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
17
|
- - ~>
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '10.1'
|
20
|
-
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirement: !ruby/object:Gem::Requirement
|
23
21
|
requirements:
|
24
22
|
- - ~>
|
25
23
|
- !ruby/object:Gem::Version
|
26
24
|
version: '10.1'
|
25
|
+
prerelease: false
|
26
|
+
type: :development
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rspec
|
29
|
-
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ~>
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '2.14'
|
34
|
-
|
35
|
-
prerelease: false
|
36
|
-
version_requirements: !ruby/object:Gem::Requirement
|
34
|
+
requirement: !ruby/object:Gem::Requirement
|
37
35
|
requirements:
|
38
36
|
- - ~>
|
39
37
|
- !ruby/object:Gem::Version
|
40
38
|
version: '2.14'
|
39
|
+
prerelease: false
|
40
|
+
type: :development
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rubygems-tasks
|
43
|
-
|
43
|
+
version_requirements: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
45
|
- - ~>
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0.2'
|
48
|
-
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
51
49
|
requirements:
|
52
50
|
- - ~>
|
53
51
|
- !ruby/object:Gem::Version
|
54
52
|
version: '0.2'
|
53
|
+
prerelease: false
|
54
|
+
type: :development
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: webrick
|
57
|
-
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - '>='
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '0'
|
62
|
-
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
62
|
+
requirement: !ruby/object:Gem::Requirement
|
65
63
|
requirements:
|
66
|
-
- -
|
64
|
+
- - '>='
|
67
65
|
- !ruby/object:Gem::Version
|
68
66
|
version: '0'
|
67
|
+
prerelease: false
|
68
|
+
type: :development
|
69
69
|
description: Utilities for waiting for various conditions
|
70
70
|
email:
|
71
71
|
- mbautin@gmail.com
|
@@ -85,29 +85,27 @@ files:
|
|
85
85
|
- spec/Rakefile
|
86
86
|
- spec/waitutil_spec.rb
|
87
87
|
- waitutil.gemspec
|
88
|
-
homepage: http://github.com/
|
88
|
+
homepage: http://github.com/rubytools/waitutil
|
89
89
|
licenses: []
|
90
90
|
metadata: {}
|
91
|
-
post_install_message:
|
91
|
+
post_install_message:
|
92
92
|
rdoc_options: []
|
93
93
|
require_paths:
|
94
94
|
- lib
|
95
95
|
required_ruby_version: !ruby/object:Gem::Requirement
|
96
96
|
requirements:
|
97
|
-
- -
|
97
|
+
- - '>='
|
98
98
|
- !ruby/object:Gem::Version
|
99
99
|
version: '0'
|
100
100
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
101
101
|
requirements:
|
102
|
-
- -
|
102
|
+
- - '>='
|
103
103
|
- !ruby/object:Gem::Version
|
104
104
|
version: '0'
|
105
105
|
requirements: []
|
106
|
-
rubyforge_project:
|
107
|
-
rubygems_version: 2.
|
108
|
-
signing_key:
|
106
|
+
rubyforge_project:
|
107
|
+
rubygems_version: 2.2.2
|
108
|
+
signing_key:
|
109
109
|
specification_version: 4
|
110
110
|
summary: Utilities for waiting for various conditions
|
111
|
-
test_files:
|
112
|
-
- spec/Rakefile
|
113
|
-
- spec/waitutil_spec.rb
|
111
|
+
test_files: []
|