Warning: This is a complete hack
A node process hosts the julia server, and passes the name of the named pipe to it as an argument.
Azure websites hosts node.js apps with IISNode. This basically does two things, activate the node process, and forward HTTP requests to is using a named pipe.
Websites doesn't restrict you to hosting JavaScript files, in fact you can start any old binary. I have had some success in hosting Go on Websites before (using node to forward requests using CGI).
Julia is a language that's been around for a couple of years. It's general purpose, with a strength in mathematical programming. I really like the syntax, and it seems to fit with the way I think about programming.
Julia has a web stack, with Morsel.jl as the 'Sinatra like' web framework. I'm playing around with some of my own ideas, built on the same stack. I've called it Jolt.jl.
Julia sits on the same networking library (libuv) as node, so I thought it would be simple to get it running on Azure. I was wrong.
Let's go through the steps I took to get it working.
- You need to bring the Julia runtime with you, so copy the
bin
andlib
folder from%HOME_DIRECTORY%\AppData\Local\Julia-0.3.2
into your repository. - You need to bring the packages too, so let's copy them in as well from your
%HOME_DIRECTORY%\.julia
directory. - Delete all the
.git
folders from the packages, and remove all the.gitignore
files. - We need to tell Julia to look locally for the packages, so you'll need to add this line to the start of your program
push!(LOAD_PATH, ".")
(we'll do this in a bit). - You need to rewrite part of the
HTTPServer
module, so it usesPipeServer
instead ofTcpServer
. This allows us to respond to requests on the named pipe. This will look something like this:
immutable HttpHandler
handle::Function
sock::Base.UVServer
events::Dict
HttpHandler(handle::Function) = new(handle, Base.PipeServer(), defaultevents)
end
- You'll need to write a new
run
method, to bind your named pipe to thePipeServer
:
export run_pipe
function run_pipe(server::Server, pipe::ASCIIString)
id_pool = 0 # Increments for each connection
sock = server.http.sock
websockets_enabled = server.websock != nothing
Base.uv_error("listen", !Base.bind(sock::Base.PipeServer, pipe))
listen(sock)
event("listen", server, 0)
while true # handle requests, Base.wait_accept blocks until a connection is made
client = Client(id_pool += 1, accept(sock))
client.parser = ClientParser(message_handler(server, client, websockets_enabled))
@async process_client(server, client, websockets_enabled)
end
end
- Remove all traces of
GnuTLS
from HttpServer (remove theusing
statement and therun_https
function). It's more trouble than it's worth! - Fix up paths in any
deps.jl
files which point to binaries on your local machine, and set to"D:\home\site\wwwroot\*
instead. - Now you can write a program. I used my Jolt.jl framework, but you can use what you like...
push!(LOAD_PATH, ".")
using HttpServer
using Jolt
using JoltView
using JoltJson
app = jolt()
app.get("/") do req, res, ctx
"hello world"
end
http = HttpHandler(app.dispatch)
server = Server(http)
run_pipe(server, ASCIIString(ARGS[1].data))
- My attempts to start the program directly from IISNode failed. Instead I wrote a node app (
server.js
) to start the Julia App.
var spawn = require('child_process').spawn;
console.log("starting julia");
var env = process.env;
env["HOMEDRIVE"] = "C:";
env["HOMEPATH"] = "\\home\\site\\wwwroot";
var julia = spawn('bin\\julia.exe',
["server.jl", process.env.port],
{
env : env,
cwd : process.cwd()
},
function callback(error, stdout, stderr){
});
julia.stdout.on('data', function (data) {
console.log(data);
});
julia.stderr.on('data', function (data) {
console.log(data);
});
julia.on('close', function (code) {
console.log('Julia exited with code ' + code);
});
- Note that it's necessary to add a couple of missing environment variables when starting the process.
- Push to Azure Websites and stand back!
Alternatively, you can just clone my repo which seems to work.