evdispatch 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +5 -0
- data/Manifest.txt +1 -0
- data/ext/revdispatch/libdispatch-0.1/src/ev_dispatch.cc +16 -0
- data/ext/revdispatch/libdispatch-0.1/src/ev_dispatch.h +15 -3
- data/ext/revdispatch/libdispatch-0.1/test/next_test.cc +4 -1
- data/ext/revdispatch/libdispatch-0.1/test/pipe_test.cc +15 -20
- data/ext/revdispatch/revdispatch.cc +21 -4
- data/ext/revdispatch/stest.rb +44 -0
- data/ext/revdispatch/test.rb +2 -2
- data/lib/evdispatch/loop.rb +12 -2
- data/lib/evdispatch/version.rb +1 -1
- data/website/index.html +4 -4
- metadata +3 -2
data/History.txt
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
== 0.2.2 2008-04-14
|
2
|
+
* Make options optional in request method
|
3
|
+
* Improve timeouts
|
4
|
+
* Add flush method, to flush out any buffered responses
|
5
|
+
|
1
6
|
== 0.2 2008-04-13
|
2
7
|
* Add HTTP headers to response
|
3
8
|
* Expose some basic libcurl options (useragent, cookie, followlocation, etc.. see libdispatch Changelog for details
|
data/Manifest.txt
CHANGED
@@ -100,6 +100,18 @@ bool Dispatch::start()
|
|
100
100
|
return (count < 100);
|
101
101
|
}
|
102
102
|
|
103
|
+
void Dispatch::flush()
|
104
|
+
{
|
105
|
+
// lock the responses
|
106
|
+
m_responses.m_lock.lock();
|
107
|
+
while( !m_responses.m_queue.empty() ){
|
108
|
+
m_responses.m_queue.pop();
|
109
|
+
}
|
110
|
+
// empty out the thread local buffer
|
111
|
+
m_responded.clear();
|
112
|
+
m_responses.m_lock.unlock();
|
113
|
+
}
|
114
|
+
|
103
115
|
// tell the background event listener to terminate
|
104
116
|
void Dispatch::stop()
|
105
117
|
{
|
@@ -245,10 +257,12 @@ Queue<Response>::POP_STATE Dispatch::wait_for_response_by_id( request_t id, Time
|
|
245
257
|
|
246
258
|
if( loc != m_responded.end() ){ return Queue<Response>::POPPED; }
|
247
259
|
|
260
|
+
timeout.update();
|
248
261
|
while( (rep = m_responses.pop_or_wait( &rstate, m_loop_started, timeout )) ) {
|
249
262
|
//printf( "rep: %s, id: %d\n", rep->name.c_str(), rep->id );
|
250
263
|
m_responded[rep->id] = rep;
|
251
264
|
if( rep->id == id ){ return rstate; }
|
265
|
+
timeout.update();
|
252
266
|
}
|
253
267
|
|
254
268
|
return rstate;
|
@@ -259,6 +273,7 @@ Response *Dispatch::get_next_response( Timer timer )
|
|
259
273
|
Response *rep = NULL;
|
260
274
|
Queue<Response>::POP_STATE rstate;
|
261
275
|
|
276
|
+
timer.update();
|
262
277
|
do {
|
263
278
|
rep = m_responses.pop_or_wait( &rstate, m_loop_started, timer );
|
264
279
|
if( rstate == Queue<Response>::EXITING ){ rep = NULL; break; }
|
@@ -276,6 +291,7 @@ Response *Dispatch::get_next_response( Timer timer )
|
|
276
291
|
else if( rep ) {
|
277
292
|
--m_pending;
|
278
293
|
}
|
294
|
+
timer.update();
|
279
295
|
|
280
296
|
} while( !rep && rstate == Queue<Response>::EXPIRED );
|
281
297
|
|
@@ -17,14 +17,22 @@ namespace EVD {
|
|
17
17
|
typedef unsigned long request_t;
|
18
18
|
|
19
19
|
struct Timer {
|
20
|
-
|
20
|
+
|
21
|
+
Timer( long int seconds, long int nanoseconds ) : m_seconds( seconds ), m_nanoseconds( nanoseconds ) { update(); }
|
22
|
+
|
23
|
+
// offset the timer from now
|
24
|
+
void update() {
|
21
25
|
struct timeval now;
|
22
26
|
current_time( &now );
|
23
|
-
m_time.tv_sec = now.tv_sec +
|
24
|
-
m_time.tv_nsec = (now.tv_usec
|
27
|
+
m_time.tv_sec = now.tv_sec + m_seconds;
|
28
|
+
m_time.tv_nsec = (now.tv_usec*1000) + m_nanoseconds;
|
29
|
+
//printf( "seconds: %ld, nanoseconds: %ld, from s: %ld, ns: %ld, based s: %ld, us: %ld\n", m_time.tv_sec, m_time.tv_nsec, m_seconds, m_nanoseconds, now.tv_sec, now.tv_usec );
|
25
30
|
}
|
31
|
+
|
26
32
|
inline static int current_time( struct timeval *now) { return gettimeofday(now, NULL); }
|
27
33
|
static double elapsed_time( struct timeval *then );
|
34
|
+
int long m_seconds;
|
35
|
+
int long m_nanoseconds;
|
28
36
|
struct timespec m_time;
|
29
37
|
};
|
30
38
|
|
@@ -146,6 +154,7 @@ namespace EVD {
|
|
146
154
|
req = m_queue.front();
|
147
155
|
}
|
148
156
|
while( !req ) {
|
157
|
+
timer.update();
|
149
158
|
m_cond.timed_wait( m_lock, timer );
|
150
159
|
if( !cond ){ *rstate = EXITING; break; }
|
151
160
|
size = m_queue.size();
|
@@ -224,6 +233,9 @@ namespace EVD {
|
|
224
233
|
// tell the background event listener to terminate
|
225
234
|
void stop();
|
226
235
|
|
236
|
+
// empty the response local buffer and queue
|
237
|
+
void flush();
|
238
|
+
|
227
239
|
request_t request( Request *req );
|
228
240
|
|
229
241
|
// from the main thread, get the next available response
|
@@ -32,7 +32,10 @@ static void run_tests( Dispatch &dispatcher, int count )
|
|
32
32
|
Response *rep = NULL;
|
33
33
|
double longest_request = 0.0;
|
34
34
|
|
35
|
-
|
35
|
+
// timer issues
|
36
|
+
Timer timeout(1,(500*1000*1000));
|
37
|
+
|
38
|
+
while( expected_response_count > 0 && (rep = dispatcher.get_next_response(timeout)) ){
|
36
39
|
if( longest_request < rep->response_time ){
|
37
40
|
longest_request = rep->response_time;
|
38
41
|
}
|
@@ -41,32 +41,27 @@ static void run_tests( Dispatch &dispatcher, int count )
|
|
41
41
|
FD_ZERO(&wr);
|
42
42
|
FD_ZERO(&er);
|
43
43
|
FD_SET(pfd[0], &rd);
|
44
|
-
tv.tv_sec =
|
44
|
+
tv.tv_sec = 1;
|
45
45
|
tv.tv_usec = 0;
|
46
46
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
break;
|
60
|
-
}
|
47
|
+
while( (retval = select( pfd[0]+1, &rd, &wr, &er, &tv )) ) {
|
48
|
+
if( retval == -1 && errno == EINTR ) { continue; }
|
49
|
+
if( retval < 0 ){ perror("select"); break; }
|
50
|
+
if( FD_ISSET(pfd[0],&rd) ){
|
51
|
+
retval = read(pfd[0],READ_BUFFER,read_size);
|
52
|
+
if( retval >= 0 ) {
|
53
|
+
result_buffer.append(READ_BUFFER,retval);
|
54
|
+
if( retval == 0 ){ break; }
|
55
|
+
}
|
56
|
+
else {
|
57
|
+
perror("read");
|
58
|
+
break;
|
61
59
|
}
|
62
60
|
}
|
63
|
-
fprintf( stderr, "loop returnd\n" );
|
64
|
-
printf("response: %s, in %.5lf seconds of Content-Length: %d bytes\n%s", res->name.c_str(), res->response_time, result_buffer.length(), res->m_header.c_str() );
|
65
|
-
delete res;
|
66
|
-
}catch(const std::exception &exp){
|
67
|
-
perror("select");
|
68
61
|
}
|
69
62
|
fprintf( stderr, "loop returnd\n" );
|
63
|
+
printf("response: %s, in %.5lf seconds of Content-Length: %d bytes\n%s", res->name.c_str(), res->response_time, result_buffer.length(), res->m_header.c_str() );
|
64
|
+
delete res;
|
70
65
|
}
|
71
66
|
|
72
67
|
int main(int argc, char **argv)
|
@@ -91,13 +91,19 @@ VALUE Loop_request_http( VALUE self, VALUE url )
|
|
91
91
|
}
|
92
92
|
|
93
93
|
static
|
94
|
-
VALUE Loop_request(
|
94
|
+
VALUE Loop_request( int argc, VALUE *argv, VALUE self )
|
95
95
|
{
|
96
96
|
EVD::Dispatch *d;
|
97
97
|
const int VALUE_BUFFER_SIZE = 1024;
|
98
98
|
char VALUE_BUFFER[VALUE_BUFFER_SIZE];
|
99
99
|
Data_Get_Struct( self, EVD::Dispatch, d );
|
100
100
|
|
101
|
+
VALUE url, options;
|
102
|
+
|
103
|
+
// required 1 argument the 'url' and 1 optional the hash of options
|
104
|
+
if( rb_scan_args( argc, argv, "11", &url, &options ) == 1 ) {
|
105
|
+
options = rb_hash_new();
|
106
|
+
}
|
101
107
|
|
102
108
|
EVD::HttpRequest *req = new EVD::HttpRequest( *d, RSTRING_PTR(url) );
|
103
109
|
|
@@ -122,7 +128,7 @@ VALUE Loop_wait_for_response( VALUE self, VALUE id, VALUE timeout_seconds, VALUE
|
|
122
128
|
|
123
129
|
Data_Get_Struct( self, EVD::Dispatch, d );
|
124
130
|
|
125
|
-
rstate = d->wait_for_response_by_id( rid, EVD::Timer(FIX2LONG(timeout_seconds), FIX2LONG(timeout_mseconds)) );
|
131
|
+
rstate = d->wait_for_response_by_id( rid, EVD::Timer(FIX2LONG(timeout_seconds), (FIX2LONG(timeout_mseconds)*1000*1000)) );
|
126
132
|
|
127
133
|
return rb_int_new(rstate);
|
128
134
|
}
|
@@ -137,7 +143,7 @@ VALUE Loop_response_for( VALUE self, VALUE id )
|
|
137
143
|
EVD::request_t rid = FIX2LONG(id);
|
138
144
|
|
139
145
|
res = (EVD::HttpResponse*)d->response_for( rid );
|
140
|
-
if( res ){
|
146
|
+
if( res ) {
|
141
147
|
|
142
148
|
VALUE result = rb_hash_new();
|
143
149
|
|
@@ -154,6 +160,16 @@ VALUE Loop_response_for( VALUE self, VALUE id )
|
|
154
160
|
return Qnil;
|
155
161
|
}
|
156
162
|
|
163
|
+
static
|
164
|
+
VALUE Loop_flush( VALUE self )
|
165
|
+
{
|
166
|
+
EVD::Dispatch *d;
|
167
|
+
Data_Get_Struct( self, EVD::Dispatch, d );
|
168
|
+
|
169
|
+
d->flush();
|
170
|
+
return Qnil;
|
171
|
+
}
|
172
|
+
|
157
173
|
static
|
158
174
|
VALUE Loop_stop( VALUE self )
|
159
175
|
{
|
@@ -191,7 +207,8 @@ extern "C" void Init_revdispatch()
|
|
191
207
|
|
192
208
|
rb_define_method( rb_Loop, "start", (VALUE (*)(...))Loop_start, 0 );
|
193
209
|
rb_define_method( rb_Loop, "request_http", (VALUE (*)(...))Loop_request_http, 1 );
|
194
|
-
rb_define_method( rb_Loop, "request", (VALUE (*)(...))Loop_request,
|
210
|
+
rb_define_method( rb_Loop, "request", (VALUE (*)(...))Loop_request, -1 );
|
211
|
+
rb_define_method( rb_Loop, "flush", (VALUE (*)(...))Loop_flush, 0 );
|
195
212
|
rb_define_method( rb_Loop, "response_for", (VALUE (*)(...))Loop_response_for, 1 );
|
196
213
|
rb_define_method( rb_Loop, "wait_for_response", (VALUE (*)(...))Loop_wait_for_response, 3 );
|
197
214
|
rb_define_method( rb_Loop, "stop", (VALUE (*)(...))Loop_stop, 0 );
|
@@ -0,0 +1,44 @@
|
|
1
|
+
$:.unshift File.join(File.dirname(__FILE__),'..','..','lib')
|
2
|
+
|
3
|
+
require 'evdispatch'
|
4
|
+
require 'test/unit'
|
5
|
+
|
6
|
+
$d = Evdispatch::Loop.new
|
7
|
+
# start the event loop thread
|
8
|
+
$d.start
|
9
|
+
|
10
|
+
class TestRequests < Test::Unit::TestCase
|
11
|
+
|
12
|
+
def test_response
|
13
|
+
id = $d.request_http("http://127.0.0.1:4044/bytes/10")
|
14
|
+
response = $d.response( id )
|
15
|
+
#puts response.inspect
|
16
|
+
#{:response_time=>0.003444, :name=>"http://127.0.0.1:4044/bytes/10", :id=>0, :body=>"CCCCCCCCCC"}
|
17
|
+
assert_equal("http://127.0.0.1:4044/bytes/10", response[:name])
|
18
|
+
assert_equal("CCCCCCCCCC", response[:body])
|
19
|
+
assert_equal("HTTP/1.1 200 OK\r\nContent-Type: text/json\r\nContent-Length: 10\r\nConnection: close\r\n\r\n", response[:header])
|
20
|
+
assert(response.keys.include?(:response_time))
|
21
|
+
assert(response.keys.include?(:id))
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_options_request
|
25
|
+
id = $d.request("http://127.0.0.1:4044/redir/1", :followlocation => 1, :referer => 'pizza')
|
26
|
+
response = $d.response( id )
|
27
|
+
assert_match(/ 302 Moved Temporarily/,response[:header])
|
28
|
+
assert_match(/ 200 OK/,response[:header])
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_delayed_with_flush
|
32
|
+
id = $d.request("http://127.0.0.1:4044/delay/0")
|
33
|
+
tid = $d.request("http://127.0.0.1:4044/delay/3")
|
34
|
+
res = $d.response( id, 1.0, 1 )
|
35
|
+
res2 = $d.response( tid, 1.0, 1 )
|
36
|
+
if !res or !res2
|
37
|
+
$d.flush # flush because we aborted before we finished, still the issue of the request is still running, but any previous responses that were delayed will be flushed
|
38
|
+
end
|
39
|
+
puts res.inspect
|
40
|
+
puts res2.inspect
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# not bothering to cleanup
|
data/ext/revdispatch/test.rb
CHANGED
@@ -62,8 +62,8 @@ def run_trial
|
|
62
62
|
|
63
63
|
ebbbase = "http://127.0.0.1:4044/"
|
64
64
|
timer = Time.now
|
65
|
-
ids = request_bytes_from( d, ebbbase,
|
66
|
-
ids += request_delay_from( d, ebbbase, 100, 1 )
|
65
|
+
ids = request_bytes_from( d, ebbbase, 400, 10000 )
|
66
|
+
#ids += request_delay_from( d, ebbbase, 100, 1 )
|
67
67
|
|
68
68
|
# wait for each response
|
69
69
|
puts "expecting #{ids.size} responses..."
|
data/lib/evdispatch/loop.rb
CHANGED
@@ -4,11 +4,21 @@ require 'revdispatch'
|
|
4
4
|
# ruby threads can execute while we waiting for a response
|
5
5
|
module Evdispatch
|
6
6
|
class Loop
|
7
|
-
def response(id)
|
8
|
-
|
7
|
+
def response(id, timeout = 1.0, max_attempts = 100)
|
8
|
+
attempts = 0
|
9
|
+
ms = timeout * 1000 # convert to miliseconds
|
10
|
+
ms_i = ms.to_i
|
11
|
+
seconds = ms_i / 1000
|
12
|
+
mseconds = (ms - (seconds*1000)).to_i
|
13
|
+
#puts "Waiting #{seconds} seconds and #{mseconds} miliseconds"
|
14
|
+
|
15
|
+
while (wait_for_response( id, seconds, mseconds ) and attempts < max_attempts )
|
9
16
|
res = response_for( id )
|
10
17
|
break if res
|
18
|
+
attempts += 1
|
19
|
+
#puts "Attempt: #{attempts}"
|
11
20
|
end
|
21
|
+
return nil if !res and attempts == max_attempts
|
12
22
|
res = response_for( id ) unless res
|
13
23
|
res
|
14
24
|
end
|
data/lib/evdispatch/version.rb
CHANGED
data/website/index.html
CHANGED
@@ -18,7 +18,7 @@
|
|
18
18
|
<h1>evdispatch</h1>
|
19
19
|
<div id="version" class="clickable" onclick='document.location = "http://rubyforge.org/projects/evdispatch"; return false'>
|
20
20
|
<p>Get Version</p>
|
21
|
-
<a href="http://rubyforge.org/projects/evdispatch" class="numbers">0.2.
|
21
|
+
<a href="http://rubyforge.org/projects/evdispatch" class="numbers">0.2.1</a>
|
22
22
|
</div>
|
23
23
|
<h4 style="float:right;padding-right:10px;">→ ‘evdispatch’</h4>
|
24
24
|
|
@@ -56,9 +56,9 @@ web applications to make multiple concurrent service requests to satisify a sing
|
|
56
56
|
|
57
57
|
<span class="keyword">class </span><span class="class">DashController</span> <span class="punct"><</span> <span class="constant">ApplicationController</span>
|
58
58
|
<span class="keyword">def </span><span class="method">index</span>
|
59
|
-
<span class="attribute">@blogs_id</span> <span class="punct">=</span> <span class="global">$dispatcher</span><span class="punct">.</span><span class="ident">
|
60
|
-
<span class="attribute">@news_id</span> <span class="punct">=</span> <span class="global">$dispatcher</span><span class="punct">.</span><span class="ident">
|
61
|
-
<span class="attribute">@messages_id</span> <span class="punct">=</span> <span class="global">$dispatcher</span><span class="punct">.</span><span class="ident">
|
59
|
+
<span class="attribute">@blogs_id</span> <span class="punct">=</span> <span class="global">$dispatcher</span><span class="punct">.</span><span class="ident">request</span><span class="punct">("</span><span class="string">http://10.0.6.45/service/blogs</span><span class="punct">")</span>
|
60
|
+
<span class="attribute">@news_id</span> <span class="punct">=</span> <span class="global">$dispatcher</span><span class="punct">.</span><span class="ident">request</span><span class="punct">("</span><span class="string">http://10.0.6.45/service/news</span><span class="punct">")</span>
|
61
|
+
<span class="attribute">@messages_id</span> <span class="punct">=</span> <span class="global">$dispatcher</span><span class="punct">.</span><span class="ident">request</span><span class="punct">("</span><span class="string">http://10.0.6.45/service/messages</span><span class="punct">")</span>
|
62
62
|
<span class="keyword">end</span>
|
63
63
|
<span class="keyword">end</span>
|
64
64
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: evdispatch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Todd A. Fisher
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-04-
|
12
|
+
date: 2008-04-14 00:00:00 -04:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -58,6 +58,7 @@ files:
|
|
58
58
|
- website/template.html.erb
|
59
59
|
- ext/revdispatch/server.rb
|
60
60
|
- ext/revdispatch/test.rb
|
61
|
+
- ext/revdispatch/stest.rb
|
61
62
|
- ext/revdispatch/extconf.rb
|
62
63
|
- ext/revdispatch/revdispatch.cc
|
63
64
|
- ext/revdispatch/libdispatch-0.1/
|