Mod_ruby or FastCGI multiple instances single file

Hi,

I’m in the process of moving from the J2EE to the Ruby world (+ Apache,
Linux, MySQL, etc.), so this is likely to be a “stupid newbie” question.

I use mod_ruby and understand that FastCGI operates along similar lines:
there is one instance of the Ruby interpreter per Apache thread, but of
course there may be lots of Apache threads, so lots of interpreters.

I want to log an event either to a log file or a database. Since this
would be executed for every download from my site I think the log file
route may be more appropriate (=faster).

My problem: “How can I write (append) to the same log file from multiple
interpreter instances at least potentially simultaneously?”

In Java, I know that my application server has multiple threads and
multiple classloaders, EARs, WARs and so on, but a single virtual
machine; I’d create a singleton to open the file and synchronize the
calls to the write method. Mission accomplished.

As I understand it Ruby will only allow me to open a file in append mode
if nobody else currently has the file open for writing/appending. So
when two interperters try to open the file at the same time, all but
one will fail.

I could loop until the file is available but that would crash my app if
the file is kept open for any reason. I could just accept that I can’t
write to the log file and forget logging the line if I can’t open the
file immediately but of course I’d be losing data… or I could write a
daemon running its own single interpreter that serializes the writes…
but surely this already exists somewhere?

This must be frequent problem and I’m sure I’m missing something? What
is it?

Thanks for your help.

Best regards,

Frank

Hello,

On Tue, 26 Sep 2006 05:28:15 +0900, Frank R. [email protected]
wrote:

My problem: “How can I write (append) to the same log file from multiple
interpreter instances at least potentially simultaneously?”

Take advantage of your operating system and use File’s flock features.
For example this code snippet should do what you are asking for:

File.open(“foo.txt”, “w”) do |f|
f.flock(File::LOCK_EX)
f.puts “Hello from #{Process.pid}”
f.flock(File::LOCK_UN)
end

Try running the above code with multiple instances of ruby and loop.
You should notice that each entry is on a new line with no data being
clipped.

I hope that helps,
Zev

On 9/25/06, Frank R. [email protected] wrote:

Hi,

I’m in the process of moving from the J2EE to the Ruby world (+ Apache,
Linux, MySQL, etc.), so this is likely to be a “stupid newbie” question.

I use mod_ruby and understand that FastCGI operates along similar lines:
there is one instance of the Ruby interpreter per Apache thread, but of
course there may be lots of Apache threads, so lots of interpreters.

No, it’s one instance of the ruby interpreter for the whole apache, as
I recently found out. Plus ruby is not thread safe. Actually most
interpreted languages are not thread safe. Perl is, and it’s the only
embeddded interpreter for apache that I know of that runs under the
worker mpm. Fastcgi is run completely outside of apache and it
communicates with apache using it’s own protocol.

On 9/25/06, Frank R. [email protected] wrote:

Hi,

I want to log an event either to a log file or a database. Since this
would be executed for every download from my site I think the log file
route may be more appropriate (=faster).

My problem: “How can I write (append) to the same log file from multiple
interpreter instances at least potentially simultaneously?”

Another possibility: write a single-threaded server on a localhost UDP
port
and have each handler in the apache process fire-and-forget a packet to
the
UDP server for each log line.

Thanks for all the great help.

I am fairly certain that I read somewhere that there is one interperter
per Apache thread, but admitedly the documentation is fairly patchy :slight_smile:
I guess I’ll find out.

As for thread-safeness: long assignement (long i = 100;) is not
thread-safe in Java (I’m not joking) because it is broken down into two
byte codes, so nothing shocks me anymore :slight_smile:

I had though of the UPD server but discarded it as too prone to
producing down time (yet another component to worry about).

The flock solution sounds like the kind of solution I’m after. I’ll give
it a try.

Zev B. wrote:

Take advantage of your operating system and use File’s flock features.
For example this code snippet should do what you are asking for:

File.open(“foo.txt”, “w”) do |f|
f.flock(File::LOCK_EX)
f.puts “Hello from #{Process.pid}”
f.flock(File::LOCK_UN)
end

Thanks again for your help.

Best regards,

Frank