waitutil 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
-
[![Build Status](https://travis-ci.org/
|
3
|
+
[![Build Status](https://travis-ci.org/rubytools/waitutil.png?branch=master)](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: []
|