FastCGI: handling the caching of ruby scripts.

J

Jonas Hartmann

FastCGIs idea of caching scripts on first startup is a great thing but:

- Sometimes you need to reload scripts
- If you are developing, reloading scripts that have been modified is
needed.

My idea was to support two ways of reloading.
1.) A GET/POST variable from HTTP can force the script to stops its
FCGI process and launches itself again after that.

2.) The script has to detect if the user-agent send an force-refresh.
(Shift+Reload in Firefox for example). If that is the case, the script
stops its FCGI process and launches itself again after that. This
behaviour can be disabled by a global variable.

I do not have any idea how to make neither 1.) nor 2.) work. How do I
detect if the user-agent send an force-reload/cache-ignore?

I cannot make the last example on this Page:
http://rubygarden.org/ruby/ruby?FCGIRubyWhyArentMyChangesDisplayed
working yet...

Any hints, tipps, suggestions?
 
D

Dick Davies

* Jonas Hartmann said:
FastCGIs idea of caching scripts on first startup is a great thing but:

- Sometimes you need to reload scripts
- If you are developing, reloading scripts that have been modified is
needed.

It's not so much that it caches, just that it doesn't exit.
My idea was to support two ways of reloading.
1.) A GET/POST variable from HTTP can force the script to stops its
FCGI process and launches itself again after that.

2.) The script has to detect if the user-agent send an force-refresh.
(Shift+Reload in Firefox for example). If that is the case, the script
stops its FCGI process and launches itself again after that. This
behaviour can be disabled by a global variable.

I do not have any idea how to make neither 1.) nor 2.) work. How do I
detect if the user-agent send an force-reload/cache-ignore?

I'm not sure that's the 'right way' - do you really want clients to tell your
app when to restart?
I cannot make the last example on this Page:
http://rubygarden.org/ruby/ruby?FCGIRubyWhyArentMyChangesDisplayed
working yet...

That should work. I did something similar (which it looks like I've since deleted)
that killed itself if it's file had changed and let apache restart it.

These days I use lighttpd running as myself to frontend my app, so I either restart it
or kill the fcgi children myself and let lighty restart them.
 
J

Jonas Hartmann

Jonas said:
FastCGIs idea of caching scripts on first startup is a great thing but:

- Sometimes you need to reload scripts
- If you are developing, reloading scripts that have been modified is
needed.

My idea was to support two ways of reloading.
1.) A GET/POST variable from HTTP can force the script to stops its FCGI
process and launches itself again after that.

2.) The script has to detect if the user-agent send an force-refresh.
(Shift+Reload in Firefox for example). If that is the case, the script
stops its FCGI process and launches itself again after that. This
behaviour can be disabled by a global variable.

I do not have any idea how to make neither 1.) nor 2.) work. How do I
detect if the user-agent send an force-reload/cache-ignore?

I cannot make the last example on this Page:

I have found a simple solution and updated this page:
 
B

Brian Candler

I cannot make the last example on this Page:
http://rubygarden.org/ruby/ruby?FCGIRubyWhyArentMyChangesDisplayed
working yet...

Which one - the "FastCgiConfig -autoUpdate" or the Thread.new ?

Both will only work if the main application file itself has updated, not any
libraries which it 'requires'

You could write something which checks all the files in $". However, those
paths are not absolute, and each one would have to be searched against $: to
find them.

Hmm, I don't see a Ruby function to search for a file in a path (strange,
maybe I'm missing something), so this gets a bit more long-winded than I
expected:

---- 8< -----------------------------------------------------------------
#!/usr/bin/env ruby

require 'fcgi'
# ... more requires

def path_search(file, pathlist)
return file if file[0..0] == File::SEPARATOR and File.exist?(file)
pathlist.each do |p|
fn = p+File::SEPARATOR+file
return fn if File.exist?(fn)
end
nil
end

Thread.new([File.expand_path(__FILE__)]) do |fname|
old_stats = {}
while true
(fname+$").each do |f|
stat = File.stat(path_search(f,$:)) rescue nil
if stat and old_stats[f]
exit if stat.mtime != old_stats[f].mtime or
stat.ino != old_stats[f].ino
end
old_stats[f] = stat
end
sleep 10
end
end

#... rest if program
---- 8< -----------------------------------------------------------------

To debug this, set "Thread.abort_on_exception=true" at the top.

I think this should work even if the number of files 'required' by the
program increases over time.

Regards,

Brian.
 
J

Jonas Hartmann

Brian said:
I cannot make the last example on this Page:
http://rubygarden.org/ruby/ruby?FCGIRubyWhyArentMyChangesDisplayed
working yet...


Which one - the "FastCgiConfig -autoUpdate" or the Thread.new ?

Both will only work if the main application file itself has updated, not any
libraries which it 'requires'

You could write something which checks all the files in $". However, those
paths are not absolute, and each one would have to be searched against $: to
find them.

Hmm, I don't see a Ruby function to search for a file in a path (strange,
maybe I'm missing something), so this gets a bit more long-winded than I
expected:

---- 8< -----------------------------------------------------------------
#!/usr/bin/env ruby

require 'fcgi'
# ... more requires

def path_search(file, pathlist)
return file if file[0..0] == File::SEPARATOR and File.exist?(file)
pathlist.each do |p|
fn = p+File::SEPARATOR+file
return fn if File.exist?(fn)
end
nil
end

Thread.new([File.expand_path(__FILE__)]) do |fname|
old_stats = {}
while true
(fname+$").each do |f|
stat = File.stat(path_search(f,$:)) rescue nil
if stat and old_stats[f]
exit if stat.mtime != old_stats[f].mtime or
stat.ino != old_stats[f].ino
end
old_stats[f] = stat
end
sleep 10
end
end

#... rest if program
---- 8< -----------------------------------------------------------------

To debug this, set "Thread.abort_on_exception=true" at the top.

I think this should work even if the number of files 'required' by the
program increases over time.

Regards,

Brian.


You are sure the -autoUpdate flag does not check files and dependencies?

foo requires bar
foo changes => autoUpdate is invoked
bar changes => foo requires a different file?

what about load and evil(eval)?
 
D

Dick Davies

* Brian Candler said:
Which one - the "FastCgiConfig -autoUpdate" or the Thread.new ?

Both will only work if the main application file itself has updated, not any

You could check out the require_dependency function in Rails, it handles
this fairly elegantly.
 
B

Brian Candler

You are sure the -autoUpdate flag does not check files and dependencies?

It's an Apache (mod_fastcgi) flag; mod_fastcgi doesn't know anything about
Ruby, to know which libraries the program depends on.
foo requires bar
foo changes => autoUpdate is invoked
yes

bar changes => foo requires a different file?

But if you change bar without changing foo, Apache doesn't know that foo has
to be reloaded.

As for foo itself, it has probably done 'require bar' once at the top of the
file. Even if foo has 'require bar' inside the main loop, require will see
that bar is in $" and will not attempt to reload it.
what about load and evil(eval)?

load will probably work, but if you load every library inside your main
loop, it will be slow. As for eval, what are you thinking of passing to
eval?

Regards,

Brian.
 

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

Members online

No members online now.

Forum statistics

Threads
474,156
Messages
2,570,878
Members
47,406
Latest member
ElizabetMo

Latest Threads

Top