A
Ara.T.Howard
URIS
http://codeforpeople.com/lib/ruby/acgi/
SYNOPSIS
as=C2=B7sid=C2=B7u=C2=B7ous (adj.)
1. constant in application or attention; diligent: an assiduous work=
er who
strove for perfection.
2. unceasing; persistent: assiduous research.
acgi : assiduous or ara's cgi (emphasis on the 'ass' in assiduous) a d=
rop-in
replacement for ruby's built-in cgi that provides copious features suc=
h as
- no apache modules
- persistence
- speed
- simplicity
- familiarity
- no apache modules
- browser neutrality
- could easily be made platform independent
- no apache modules
- no special webserver setup or system privledges required
- ability to install to a webserver via ftp
- no apache modules
- session affinity, all request handled by one process
- automatic reload if code changes
- ability to run script simulaneously as acgi and cgi for debuggging
- ability to easily start/stop/restart/check-on running server
- 178 lines of ruby code (and one c program)
- no apache modules
PERFORMANCE
case one, a simple cgi that just dumps the environment:
with acgi:
[ahoward@localhost acgi-0.1.0]$ ab -n100 -c4 http://localhost/acgi/a=
cgi-0.1.0/ | grep 'Requests per second'
Requests per second: 74.93 [#/sec] (mean)
without:
[ahoward@localhost acgi-0.1.0]$ ab -n100 -c4 http://localhost/acgi/a=
cgi-0.1.0/server.cgi | grep 'Requests per second'
Requests per second: 18.76 [#/sec] (mean)
a more realistic cgi that uses sessions and sleeps for 1 second to mim=
ic
connecting to a database:
with acgi:
[ahoward@localhost acgi-0.1.0]$ ab -n100 -c4 http://localhost/acgi/a=
cgi-0.1.0/ | grep 'Requests per second'
Requests per second: 24.20 [#/sec] (mean)
without:
[ahoward@localhost acgi-0.1.0]$ ab -n100 -c4 http://localhost/acgi/a=
cgi-0.1.0/server.cgi | grep 'Requests per second'
Requests per second: 3.63 [#/sec] (mean)
ARCHITECHTURE
the design of acgi is similar to that of fastcgi (http://www.fastcgi.c=
om) but
requires no external modules, configuration of apache, etc.
a acgi application consists of a cgi server backend which loops, handl=
ing all
incoming requests; the requests are delegated to this backend server v=
ia a
simple, fast to start up, 'index.cgi' program written in c. communica=
tion
between 'index.cgi' and it's backend server is via named pipes (fifos)=
:
-------------
| index.cgi | <- transient compiled c c=
ode
-------------
| | |
| fifos for stderr, stdout, stdin, env
| | |
/ | \
------------------------------
| |
| cgi server | <- persistent looping rub=
y code
| |
------------------------------
note that the architechture is similar in spirit to fastcgi - it provi=
des
speed by avoiding startup overhead and redundant work like database co=
nnection
setup. in this case, contrasted with fastcgi, the whole thing takes p=
lace
outside of the webserver in the application domain and, therfore, comm=
unicates
via named pipes rather than unix domain sockets.
REQUEST CYCLE
- request comes in to web server
- request is passed to index.cgi which, itself, is a very simple compi=
led c
program (ultra fast startup time) which in turn does the following
- make sure the ruby server is running, spawn it in the background=
iff
required. this is a non-blocking operation that functions as a =
simple
process manager in order to ensure a server is running at all ti=
mes.
- aqurire a lock (fcntl) to prevent any other concurrent invocatio=
ns of
index.cgi from overlapping - all invocations procede one at a ti=
me in
the order of receipt. there are never concurrent requests to th=
e
server. we can't all send data down the pipe at once.
- serialize the environment and send it down the pipe
- read any stderr/stdout from the ruby server via fifos and write =
them to
stderr/stdout respectively. stdout and stderr go to the 'normal=
' places
- the client and webserver log respectively.
- release lock - automatic when index.cgi process dies anyhow
- the ruby server, for it's part, does the following
- aquire a lock which prevent multiple copies of itself from running
simoultaneously. this is the same lock the c program checks in a
non-blocking fashion to see if the server is running.
- loops doing the following
- loading the environment
- handling request with stderr/stdout/stdin redirected to pipes be=
ing read
by index.cgi, the compiled c program
this cycle is mostly transparent to the cgi progam. for instace, to c=
onvert
an existing cgi program into an acgi program one would simply change
require 'cgi'
cgi =3D CGI::new
cgi.out{ content }
to
require 'cgi'
require 'acgi
ACGI::each_cgi do |cgi|
cgi.out{ content }
end
the same cgi script acts both as the backend to the index.cgi c progra=
m and
the frontend to any 'normal' cgi requests. the works as follows: say=
you
name your cgi program 'server.cgi' and it lives in a directory under t=
he
webroot like so
acgi/server.cgi
acgi/index.cgi
then, assuming a webserver setup that uses index.cgi for directory ind=
exing,
one can hit a url like
http://localhost/acgi/
or
http://localhost/acgi/index.cgi
and the fast version will be run. hitting
http://localhost/acgi/server.cgi
results in normal (slow) cgi mode - useful for debugging.
IMPLEMENTATION
shoddy - but getting better (note move to 0.1.0 !!).
this version is proof of concept only!!! it's likely to run only on l=
inux,
though it may run on many *nix platforms. or maybe not. the sun coul=
d
explode if you run the example program. security is not considered.
RUNNING THE EXAMPLE
- unpack tarball in webroot
- make
- point browser at
http:://your.host.com/path/where/you/unpacked/
to see the acgi version or
- point browser at
http:://your.host.com/path/where/you/unpacked/server.cgi
to see the slow cgi version
obviously you'll need cgi setup for you web server, index.cgi set for
directory index, ruby installed, etc. but nothing out of the ordinary=
http://codeforpeople.com/lib/ruby/acgi/
SYNOPSIS
as=C2=B7sid=C2=B7u=C2=B7ous (adj.)
1. constant in application or attention; diligent: an assiduous work=
er who
strove for perfection.
2. unceasing; persistent: assiduous research.
acgi : assiduous or ara's cgi (emphasis on the 'ass' in assiduous) a d=
rop-in
replacement for ruby's built-in cgi that provides copious features suc=
h as
- no apache modules
- persistence
- speed
- simplicity
- familiarity
- no apache modules
- browser neutrality
- could easily be made platform independent
- no apache modules
- no special webserver setup or system privledges required
- ability to install to a webserver via ftp
- no apache modules
- session affinity, all request handled by one process
- automatic reload if code changes
- ability to run script simulaneously as acgi and cgi for debuggging
- ability to easily start/stop/restart/check-on running server
- 178 lines of ruby code (and one c program)
- no apache modules
PERFORMANCE
case one, a simple cgi that just dumps the environment:
with acgi:
[ahoward@localhost acgi-0.1.0]$ ab -n100 -c4 http://localhost/acgi/a=
cgi-0.1.0/ | grep 'Requests per second'
Requests per second: 74.93 [#/sec] (mean)
without:
[ahoward@localhost acgi-0.1.0]$ ab -n100 -c4 http://localhost/acgi/a=
cgi-0.1.0/server.cgi | grep 'Requests per second'
Requests per second: 18.76 [#/sec] (mean)
a more realistic cgi that uses sessions and sleeps for 1 second to mim=
ic
connecting to a database:
with acgi:
[ahoward@localhost acgi-0.1.0]$ ab -n100 -c4 http://localhost/acgi/a=
cgi-0.1.0/ | grep 'Requests per second'
Requests per second: 24.20 [#/sec] (mean)
without:
[ahoward@localhost acgi-0.1.0]$ ab -n100 -c4 http://localhost/acgi/a=
cgi-0.1.0/server.cgi | grep 'Requests per second'
Requests per second: 3.63 [#/sec] (mean)
ARCHITECHTURE
the design of acgi is similar to that of fastcgi (http://www.fastcgi.c=
om) but
requires no external modules, configuration of apache, etc.
a acgi application consists of a cgi server backend which loops, handl=
ing all
incoming requests; the requests are delegated to this backend server v=
ia a
simple, fast to start up, 'index.cgi' program written in c. communica=
tion
between 'index.cgi' and it's backend server is via named pipes (fifos)=
:
-------------
| index.cgi | <- transient compiled c c=
ode
-------------
| | |
| fifos for stderr, stdout, stdin, env
| | |
/ | \
------------------------------
| |
| cgi server | <- persistent looping rub=
y code
| |
------------------------------
note that the architechture is similar in spirit to fastcgi - it provi=
des
speed by avoiding startup overhead and redundant work like database co=
nnection
setup. in this case, contrasted with fastcgi, the whole thing takes p=
lace
outside of the webserver in the application domain and, therfore, comm=
unicates
via named pipes rather than unix domain sockets.
REQUEST CYCLE
- request comes in to web server
- request is passed to index.cgi which, itself, is a very simple compi=
led c
program (ultra fast startup time) which in turn does the following
- make sure the ruby server is running, spawn it in the background=
iff
required. this is a non-blocking operation that functions as a =
simple
process manager in order to ensure a server is running at all ti=
mes.
- aqurire a lock (fcntl) to prevent any other concurrent invocatio=
ns of
index.cgi from overlapping - all invocations procede one at a ti=
me in
the order of receipt. there are never concurrent requests to th=
e
server. we can't all send data down the pipe at once.
- serialize the environment and send it down the pipe
- read any stderr/stdout from the ruby server via fifos and write =
them to
stderr/stdout respectively. stdout and stderr go to the 'normal=
' places
- the client and webserver log respectively.
- release lock - automatic when index.cgi process dies anyhow
- the ruby server, for it's part, does the following
- aquire a lock which prevent multiple copies of itself from running
simoultaneously. this is the same lock the c program checks in a
non-blocking fashion to see if the server is running.
- loops doing the following
- loading the environment
- handling request with stderr/stdout/stdin redirected to pipes be=
ing read
by index.cgi, the compiled c program
this cycle is mostly transparent to the cgi progam. for instace, to c=
onvert
an existing cgi program into an acgi program one would simply change
require 'cgi'
cgi =3D CGI::new
cgi.out{ content }
to
require 'cgi'
require 'acgi
ACGI::each_cgi do |cgi|
cgi.out{ content }
end
the same cgi script acts both as the backend to the index.cgi c progra=
m and
the frontend to any 'normal' cgi requests. the works as follows: say=
you
name your cgi program 'server.cgi' and it lives in a directory under t=
he
webroot like so
acgi/server.cgi
acgi/index.cgi
then, assuming a webserver setup that uses index.cgi for directory ind=
exing,
one can hit a url like
http://localhost/acgi/
or
http://localhost/acgi/index.cgi
and the fast version will be run. hitting
http://localhost/acgi/server.cgi
results in normal (slow) cgi mode - useful for debugging.
IMPLEMENTATION
shoddy - but getting better (note move to 0.1.0 !!).
this version is proof of concept only!!! it's likely to run only on l=
inux,
though it may run on many *nix platforms. or maybe not. the sun coul=
d
explode if you run the example program. security is not considered.
RUNNING THE EXAMPLE
- unpack tarball in webroot
- make
- point browser at
http:://your.host.com/path/where/you/unpacked/
to see the acgi version or
- point browser at
http:://your.host.com/path/where/you/unpacked/server.cgi
to see the slow cgi version
obviously you'll need cgi setup for you web server, index.cgi set for
directory index, ruby installed, etc. but nothing out of the ordinary=