Integrating uWSGI with Erlang
Starting from the 0.9.5 release, the uWSGI server can act as an Erlang C-Node and exchange messages and rpc with Erlang nodes.
First of all you need the erl_interface libraries and headers (they are included in the official erlang tarball, or if you are on a debian/ubuntu system you can get the erlang-dev package) then edit your uwsgiconfig.py file and set the ERLANG constant to True.
Launch make and your new uWSGI server will be compiled with Erlang support.
There are only two commandline/xml options to activate Erlang support:
--erlang <node>
--erlang-cookie <cookie>
The first one, set the erlang node name of your uWSGI server and must be in this format:
nodename@ip
where ip is the ip where your uWSGI server is bound.
The --erlang-cookie option set the cookie for inter-node communications. If you do not specify it, the value is taken from the .erlang.cookie file in your home directory.
Enabling erlang steal a worker, so you will have to ensure that you have at least one worker for python apps and one worker for erlang c-node. (But do not worry, the uWSGI server will signal unavailability of workers).
So, lets run our uWSGI-erlang-enabled server:
uwsgi --socket :3031 --erlang testnode@192.168.173.15 --erlang-cookie UUWSGIUWSGIU -p 2 ... spawned uWSGI worker 1 (pid: 26760) spawned uWSGI worker 2 (pid: 26761) Erlang mode enabled for worker 2. - you have not defined a uwsgi.erlang_func callable, Erlang message manager will be disabled until you define it -
Do not pay attention to the last warning, we will came back to it later.
You server is now ready to exchange messages with other erlang nodes.
We will start with a simple example.
A simple RPC hello world example
Define a new erlang module that exports only a simple function:
-module(uwsgitest).
-export([hello/0]).
hello() ->
'hello world !'.
now launch the erl shell specifying the nodename (in the form nodename@ip) and eventually the cookie:
erl -name testnode@192.168.173.1
compile the uwsgitest module
c(uwsgitest).
{ok,uwsgitest}
and try to run the hello function:
uwsgitest:hello(). 'hello world !'
Our Erlang module is working, we are now ready for rpc !!!
Return to your uWSGI server machine and define a new WSGI module (call it erhello.py):
import uwsgi
def application(env, start_response):
testnode = uwsgi.erlang_connect("testnode@192.168.173.1")
start_response('200 OK', [('Content-Type', 'text/plain')])
yield uwsgi.erlang_rpc(testnode, "uwsgitest", "hello", [])
uwsgi.erlang_close(testnode)
relaunch the uWSGI server with this new module
uwsgi --socket :3031 --erlang testnode@192.168.173.15 --erlang-cookie UUWSGIUWSGIU -p 2 -w erhello
Point your browser to you uwsgi-enabled webserver and you will see the output of your erlang rpc.
Python < - > Erlang mappings
The uWSGI server try to translate the Erlang types to Python Objects.
In the next table you will find the variuos correspondence:
| Python | Erlang | note |
| string | atom | |
| int/long | int | |
| list | list | |
| tuple | tuple | |
| dictionary | pid | pid is the form {'node':'N', 'number':X, 'serial':Y, 'creation':Z} |
Remember that Erlang has no real strings, it only manages "list of chars" with a sintactic sugar so:
"ABC" == [65, 66, 67].
Python strings are converted to ATOM, so if you want to convert a python string to a Erlang "list of chars" you can use this simple function:
def erlist(s):
return map(ord, list(s))
Sending messages to erlang nodes
One of the most powerful features of Erlang is its extremely-usable inter-nodes message passing. uWSGI can send (and receive) messages to (and from) erlang nodes.
Lets define a new erlang module that simply will echo back whatever we send to it:
-module(uwsgiecho).
-export([start/0, loop/0, echo/1]).
echo(Message) ->
{i_am_echo , Message}.
loop() ->
receive
Message1 ->
io:format("received a message~n"),
{ useless, 'testnode@192.168.173.15' } ! echo(Message1)
end,
loop().
start() ->
register(echoer, spawn(uwsgiecho, loop, [])).
Remember to register your process with the register function, as using Pid to identify processes is a pain in the !*#@
Now you can send messages with:
uwsgi.erlang_send_message(node, "echoer", "Hello echo server !!!" )
Look at the second argument, it is the registered process name. If you do not specify it you have to pass a Pid (using a python dictionary).
If your erlang server returns messages to your requests you can receive them with:
uwsgi.erlang_recv_message(node)
Remember that even if erlang need a process name/pid to send messages, they will be ignored by uWSGI. (look at the useless atom in the uwsgiecho code before)
Receiving erlang messages
Sometimes you want to directly send messages from an Erlang node to the uWSGI server. The worker erlang stolen on uWSGI startup, will serve for this purpose.
In your WSGI module define the uwsgi.erlang_func attribute. When the erlang-enabled worker receive a message it parse and pass it as an argument of the uwsgi.erlang_func callable:
import uwsgi
def erman(arg)
print "received an erlang message"
print arg
uwsgi.erlang_func = erman
Timeout
By default every "blocking" erlang-related-functions will set the default uWSGI internal socket timeout. If you want to modify it you can pass a last argument to uwsgi.erlang_rpc and uwsgi_erlang_recv_message functions defining the timeout (in seconds) after the call will be closed.
Opening connections
On high-loaded site opening and closing connections for every erlang-interaction is overkill.
Open the connection on your app initialization and save the file descriptor.
Remember that uwsgi.erlang_connect will return a value < 0 on errors
What about Mnesia ?
We suggest you to use Mnesia when you need an high-availability site. Simply build an erlang module that exposes all the database interaction you need and launch uwsgi.erlang_rpc to interact with it.
Can i run EWGI applications on top of uWSGI ?
The best way would be developing a plugin and assigning a special modifier for EWGI apps.
But until it will be available you can wrap the request in your WSGI callable and build the EWGI environment to pass as an argument via uwsgi.erlang_rpc
The EWGI specs are defined here: http://code.google.com/p/ewgi/wiki/EWGISpecification
