Re-posted from: http://thenewphalls.wordpress.com/2014/02/15/julia-and-apache/
Julia caught my attention recently. As I understand it, it’s intended to be a fast, all-purpose language, so that we need not have one language for scripting, one for parallel programming, another for mathematics, etc. As someone who works primarily with the web – an area where Julia is reportedly lacking – I decided to see how it would fare in that arena.
I’ll clarify this early: Julia is still in its infancy. The stable release at the time of writing is version 0.2. It’s likely that difficulties like those I encountered will be ironed out as the project evolves.
I figured (very wrongly) that the quickest and easiest way to get up and running would be to configure Apache to run .jl files as CGI. That didn’t work out the way that I hoped it would – and after an hour of basic debugging, it became clear that I had two choices: 1) use a Julia HTTP server or 2) potentially spend hours of my life figuring out why it wasn’t working – and just maybe find a workaround. If you’re familiar with this blog, you’ll know which option I went for.
Debugging – Apache
Apache was giving me the “End of script output before headers” 500 error page. The Julia code I was testing was supposed to write logs to a file to confirm that it was running, which worked fine in the console window, but there was no file activity when I loaded the page in my browser, suggesting the program/script wasn’t even being executed.
I ruled out file permissions as a cause. The CGI error log was useless (for reasons which now make sense). I was flying blind – so I tried something else…
Debugging – CGI proxy
I wrote a C program to be invoked by Apache instead of Julia. The proxy would execute Julia itself, giving me a console window with some I/O so that I could hopefully get a better idea of what was going on. Using this, I was able to identify two issues:
Issue 1: Environment variables.
Julia is hard-coded to access the APPDATA environment variable. This isn’t an issue when running from the console, but the environment created by mod_cgi doesn’t contain this variable. I was able to work around this by having an APPDATA variable be set in either the .htaccess or httpd.conf using SetEnv (see far below).
Issue 2: Julia’s bizarre I/O
I don’t mind admitting that I’m unfamiliar with the I/O library used by Julia. However, given some of the errors I was getting in my console window (inability to open I/O pipe, unsupported stdio handles, etc) and one of the pull requests on the repository, I figured that Julia 0.2 must just be incompatible with the way mod_cgi was trying to redirect the child process’ I/O. It was with this that I decided to try the (potentially unstable) build of Julia 0.3.
At the time of writing, version 0.3 is a prerelease version – which is why I first chose to use 0.2.
Using my CGI proxy, I was able to see that Julia 0.3 requires two more environment variables: HOMEDRIVE and HOMEPATH. These can be set in either the httpd.conf or .htaccess as with APPDATA.
I could also see straight away that 0.3 had a better rapport with I/O handles. After some more experimentation, I felt confident enough to direct mod_cgi to invoke julia-basic.exe directly.
Putting it all together…
Download Julia 0.3+
Configure Apache to handle .jl files as CGI scripts and set the required environment variables (APPDATA, HOMEDRIVE, HOMEPATH). Below is an example from my own httpd-vhosts.conf:
<VirtualHost localhost:80> Options +ExecCGI AddHandler cgi-script .jl SetEnv APPDATA "G:/Dev/appdata" SetEnv HOMEDRIVE "C:" SetEnv HOMEPATH "/Users/Phalls" ScriptLog logs/julia_cgi.log DocumentRoot "D:/htdocs" ServerName localhost </VirtualHost>
Restart Apache (or just reload config if you have that option).
… and that should be all there is to it. As with the likes of Perl and Ruby, the first line of your .jl files should be the path to the Julia binary. I chose to use julia-basic.exe, but I also tried it with julia-readline.exe and it was no different.
Below is some example code:
#!"G:\\Julia3\\bin\\julia-basic" redirect_stderr(STDOUT) print("Content-Type: text/html\n\n") print("<html> <body> <b>Hello, world!</b> </body> </html>")
(language=”scala” is the closest I could get to Julia for syntax highlighting)
On line 2 (i.e. 1) I redirect STDERR to STDOUT because errors (e.g. syntax errors) sent to STDERR cause Apache to hang and display a 500 error page. Redirecting to STDOUT shows the error message on the page, which is cleaner and more helpful for debugging. It may even be possible to redirect STDERR to something else, such as a stream or an IOBuffer where it can be handled in a more controlled manner.
Line 3 (i.e. 2) just outputs a header. Bear in mind that, with Julia not being strictly CGI-compatible, that becomes your app’s responsibility.
Next on the “to do” list:
- Compare performance vs Ruby and PHP
- Compare Apache/CGI performance vs HttpServer.jl
- Write basic web framework (despite this)
Estimated delivery date: I’ll get to it when I get to it.