evdispatch 0.2.1 → 0.2.2
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.
- 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/
|