webrick, threads, and i/o

A

Ara.T.Howard

if i want to write a webrick application that mounts many servlets do i need
to be concerned that, if one of the servlets blocks on i/o, the entire
(threaded) webserver will also be blocked?

-a
====================================
| Ara Howard
| NOAA Forecast Systems Laboratory
| Information and Technology Services
| Data Systems Group
| R/FST 325 Broadway
| Boulder, CO 80305-3328
| Email: (e-mail address removed)
| Phone: 303-497-7238
| Fax: 303-497-7259
| The difference between art and science is that science is what we understand
| well enough to explain to a computer. Art is everything else.
| -- Donald Knuth, "Discover"
| ~ > /bin/sh -c 'for lang in ruby perl; do $lang -e "print \"\x3a\x2d\x29\x0a\""; done'
====================================
 
N

NAKAMURA, Hiroshi

Hi,
From: "Ara.T.Howard" <[email protected]>
Sent: Saturday, October 04, 2003 11:12 AM
if i want to write a webrick application that mounts many servlets do i need
to be concerned that, if one of the servlets blocks on i/o, the entire
(threaded) webserver will also be blocked?

No. WEBrick creates worker thread for each request.
So, take care if you mount a servlet factory which returns
singleton servlet instance. It runs under MT condition.

Regards,
// NaHi
 
A

Ara.T.Howard

Hi,



No. WEBrick creates worker thread for each request.
So, take care if you mount a servlet factory which returns
singleton servlet instance. It runs under MT condition.

Regards,
// NaHi

my earlier post could have used an example, here is an example of where
blocking in one request seems to block the entire server:


----CUT----
#!/usr/local/ruby-1.8.0/bin/ruby
require 'webrick'
include WEBrick

system 'mkfifo fifo' rescue nil

port = (ARGV[0] or 2003).to_i
s = HTTPServer.new( :port => port )

#res.body = "<HTML>hello, world.</HTML>"
#res['Content-Type'] = "text/html"


class TimeServlet < HTTPServlet::AbstractServlet
def do_GET(req, res)
res['Content-Type'] = "text/plain"
res.body = Time.now.to_s
end
end

class ReadServlet < HTTPServlet::AbstractServlet
def do_GET(req, res)
res['Content-Type'] = "text/plain"
fifo = open 'fifo', 'r'
res.body = fifo.read
end
end

class WriteServlet < HTTPServlet::AbstractServlet
def do_GET(req, res)
res['Content-Type'] = "text/plain"
fifo = open 'fifo', 'w'
msg = "%s:%s" % [self.class, Time.now.to_s]
fifo.puts msg
res.body = "wrote <%s>" % [msg]
end
end

s.mount("/write", WriteServlet)
s.mount("/read", ReadServlet)
s.mount("/time", TimeServlet)
trap("INT"){ s.shutdown }
s.start
----CUT----

now, if you run this and then point your browser at

http://127.0.0.1:2003/time

you will see the time. however, if you then try one, or more, of the
following in any order

http://127.0.0.1:2003/read
http://127.0.0.1:2003/write

and return to

http://127.0.0.1:2003/time

you will see ALL windows hanging. does this make sense? how does one go
about designing servlets which will then block, like POST servlets, in a way
that would not block the entire webserver?

thanks.

-a
====================================
| Ara Howard
| NOAA Forecast Systems Laboratory
| Information and Technology Services
| Data Systems Group
| R/FST 325 Broadway
| Boulder, CO 80305-3328
| Email: (e-mail address removed)
| Phone: 303-497-7238
| Fax: 303-497-7259
| The difference between art and science is that science is what we understand
| well enough to explain to a computer. Art is everything else.
| -- Donald Knuth, "Discover"
| ~ > /bin/sh -c 'for lang in ruby perl; do $lang -e "print \"\x3a\x2d\x29\x0a\""; done'
====================================
 
N

NAKAMURA, Hiroshi

Hi,
From: "Ara.T.Howard" <[email protected]>
Sent: Saturday, October 04, 2003 3:13 PM
my earlier post could have used an example, here is an example of where
blocking in one request seems to block the entire server:

I didn't check the article, but...
fifo = open 'fifo', 'r'
res.body = fifo.read

You open fifo with blocking mode and read here. Blocking entire process
here is expected behavior if I understand correctly.
fifo = open 'fifo', 'w'
msg = "%s:%s" % [self.class, Time.now.to_s]
fifo.puts msg
now, if you run this and then point your browser at

http://127.0.0.1:2003/time

you will see the time. however, if you then try one, or more, of the
following in any order

http://127.0.0.1:2003/read
http://127.0.0.1:2003/write

I think the process is blocked at the second access. Does third
access works?
you will see ALL windows hanging. does this make sense? how does one go
about designing servlets which will then block, like POST servlets, in a way
that would not block the entire webserver?

You can open fifo with File::RDONLY|File::NONBLOCK for read side and
File::WRONLY|File::NONBLOCK for write side. I think it should work.

In other words, if you want the server never blocks no matter what
servlets do, you should use other process forking WWW server application,
or should make your server using WEBrick as a toolkit.

Regards,
// NaHi
 
A

Ara.T.Howard

You open fifo with blocking mode and read here. Blocking entire process
here is expected behavior if I understand correctly.

o.k. - that is what i was trying to confirm: that one must be careful using
webrick when doing something in a servlet that could block a process in the
kernel... good (and not unexpected) to know.
I think the process is blocked at the second access. Does third
access works?

no!? i think it's a case of thread starvation here. one servlet is blocked
opening the fifo for reading, but the other cannot open it for writing since
the entire process has halting on the first open...
You can open fifo with File::RDONLY|File::NONBLOCK for read side and
File::WRONLY|File::NONBLOCK for write side. I think it should work.

strangley, this does not work:

----CUT----
#!/usr/local/ruby-1.8.0/bin/ruby
require 'webrick'
include WEBrick

# or set this up by hand before!
system 'mkfifo fifo && chmod 777 fifo' rescue nil

port = (ARGV[0] or 2003).to_i
s = HTTPServer.new( :port => port )

class TimeServlet < HTTPServlet::AbstractServlet
def do_GET(req, res)
res['Content-Type'] = "text/plain"
res.body = Time.now.to_s
end
end

class ReadServlet < HTTPServlet::AbstractServlet
def do_GET(req, res)
res['Content-Type'] = "text/plain"
res.body =
begin
fifo = open 'fifo', File::RDWR|File::NONBLOCK
begin
fifo.read
rescue Errno::EWOULDBLOCK
'NO DATA'
end
rescue Exception => e
e.to_s << "\n" << e.backtrace.join("\n")
end
end
end

class WriteServlet < HTTPServlet::AbstractServlet
def do_GET(req, res)
res['Content-Type'] = "text/plain"
res.body =
begin
fifo = open 'fifo', File::RDWR|File::NONBLOCK
begin
msg = "%s:%s" % [self.class, Time.now.to_s]
fifo.puts msg
fifo.flush
"WROTE <%s>" % [msg]
rescue Errno::EWOULDBLOCK
'COULD NOT WRITE'
end
rescue Exception => e
e.to_s << "\n" << e.backtrace.join("\n")
end
end
end

s.mount("/write", WriteServlet)
s.mount("/read", ReadServlet)
s.mount("/time", TimeServlet)
trap("INT"){ s.shutdown }
s.start
----CUT----


while this does:
----CUT----
#!/usr/local/ruby-1.8.0/bin/ruby

system 'mkfifo fifo && chmod 777 fifo' rescue nil
r = open 'fifo', File::RDWR|File::NONBLOCK
w = open 'fifo', File::RDWR|File::NONBLOCK
w.puts 'hi'
w.flush
puts r.gets
----CUT----

so i think the logic in my servlets is correct. this is very strange?!

what's really strange about the above is that the WriteServlet DOES work, only
the ReadServlet hangs in the browser. however, even when it hanging the other
servlets (Write, Time) continue to work, so it is not as if the _process_ is
blocked, only the ReadServlet request thread!?
In other words, if you want the server never blocks no matter what servlets
do, you should use other process forking WWW server application, or should
make your server using WEBrick as a toolkit.

well - the first would require NOT using ruby so that's NOT an option! ;-)

as for the second, i'm unsure as to the best way to accomplish blocking
tasking from servlets:

a) have a dedicated worker thread so all, IO for example, is done carefully
there...

b) fire up a Drb object (in another process) and use it to perform, for
example, io. (does Drb work on windows?)

??

any other ideas?


thanks very much.

-a
====================================
| Ara Howard
| NOAA Forecast Systems Laboratory
| Information and Technology Services
| Data Systems Group
| R/FST 325 Broadway
| Boulder, CO 80305-3328
| Email: (e-mail address removed)
| Phone: 303-497-7238
| Fax: 303-497-7259
| The difference between art and science is that science is what we understand
| well enough to explain to a computer. Art is everything else.
| -- Donald Knuth, "Discover"
| ~ > /bin/sh -c 'for lang in ruby perl; do $lang -e "print \"\x3a\x2d\x29\x0a\""; done'
====================================
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Similar Threads

webrick - max_osx, windoze, and linux 1
webrick and ruby 7
1.8,frozen, and untaint 1
pstore on windoze 0
lynx, ruby-cgi, and mutipart/form 0
windows help! 3
rdtool -r rd2html-lib : HELP 0
wiki reccomendations 5

Members online

Forum statistics

Threads
473,994
Messages
2,570,223
Members
46,812
Latest member
GracielaWa

Latest Threads

Top