Skip to content

Commit

Permalink
Lua and JVM and Python decorators and and and...
Browse files Browse the repository at this point in the history
  • Loading branch information
akx committed Nov 18, 2012
1 parent d0995d9 commit ca9b1c9
Show file tree
Hide file tree
Showing 8 changed files with 693 additions and 0 deletions.
23 changes: 23 additions & 0 deletions JVM.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
JVM in the uWSGI server
=======================

.. toctree::

JWSGI

.. note:: This documentation may be out of date.

Starting from 0.9.7-dev version, a plugin that embeds a Java Virtual Machine in uWSGI is available.

Its main purpose is to allow other plugins (languages) to communicate with Java classes. The first plugin to get JVM support will be Python.

This is the current list of functions that will be exposed:

* uwsgi.jvm.call_static_method("class","method", args, ...)
* uwsgi.jvm.call_method(object,"method", args, ...)
* uwsgi.jvm.string("string")
* uwsgi.jvm.integer(N)
* uwsgi.jvm.array(object, ...)

The ``pyjvm`` plugin is still at early stage of development. The JVM plugin will allow to map string, integers and array to other languages object (in a similar way to the Erlang one).

117 changes: 117 additions & 0 deletions JWSGI.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
The JWSGI interface
===================

.. note:: JWSGI is not a standard. Yet. If you like JWSGI, why not send an RFC to the uWSGI mailing list. We have no interest in a standard, but who knows...

JWSGI is a port of the WSGI/PSGI/Rack way of thinking for Java.

If, for some obscure reason, you'd feel like developing apps with JVM languages and you don't feel like deploying a huge servlet stack, JWSGI should be up your alley.

It is a very simple (and admittedly raw) protocol where you call a public method that takes a ``Hashtable`` as its sole argument.
This Hashtable contains CGI style variables and ``jwsgi.input`` containing a Java FileDescriptor that you can use with ``java.io``.

Example
-------

A simple JWSGI app looks like this:

.. code-block:: java
import java.util.Hashtable;
import java.util.ArrayList;
public class utest {
public static Object[] jwsgi(Hashtable env) {
String status = "200 Ok";
ArrayList<Object> headers = new ArrayList<Object>();
String[] header = {"Content-type", "text/html"};
headers.add(header);
String[] header2 = {"Server", "uWSGI"};
headers.add(header2);
String body = "<h1>Hello World</h1>" + env.get("REQUEST_URI");
Object[] response = {status, headers, body};
return response;
}
}
And to consume HTTP body content,

.. code-block:: java
public static Object[] jwsgi(Hashtable env) throws java.io.IOException {
if (env.containsKey("CONTENT_LENGTH")) {
String s = (String) env.get("CONTENT_LENGTH");
if (s.length() > 0) {
Integer cl = Integer.parseInt( s );
FileInputStream f = new FileInputStream( (FileDescriptor) env.get("jwsgi.input") );
byte[] b = new byte[cl];
if (f.read(b) > 0) {
String postdata = new String(b);
System.out.println( postdata );
}
}
}
String status = "200 Ok";
ArrayList<Object> headers = new ArrayList<Object>();
String[] header = { "Content-type", "text/html" } ;
headers.add(header);
String[] header2 = { "Server", "uWSGI" } ;
headers.add(header2);
String body = "<form method=\"POST\"><input type=\"text\" name=\"nome\"/><input type=\"submit\" value=\"send\" /></form>" + env.get("REQUEST_URI");
Object[] response = { status, headers, body };
return response;
}
How to use it?
--------------

The procedure to run JWSGI is still sort of messy. You have to build both the JVM and the JWSGI plugins. Modifier 8 has been assigned to the JWSGI interface, so remember to edit your webserver
configuration accordingly.

1. Edit ``plugins/jvm/uwsgiplugin.py`` to set ``JVM_INCPATH`` and ``JVM_LIBPATH`` to their right values. What the right values are is system dependent. Search for ``jni.h`` and ``libjvm.so``.
Do the same for ``plugins/jwsgi/uwsgiplugin.py``.

2. Build!

.. code-block:: sh
python uwsgiconfig.py --build core
python uwsgiconfig.py --plugin plugins/jvm core
python uwsgiconfig.py --plugin plugins/jwsgi core
3. Compile your class with ``javac``.

.. code-block:: sh
javac utest.java
4. Run uWSGI and load the utest class.

.. code-block:: sh
./uwsgi -s :3031 --plugins jvm,jwsgi --jvm-main-class utest -M -p 4 -m
Important Notes
---------------

* The jwsgi method must be called ``jwsgi``. This will be fixed soon.
* The jwsgi plugin leaks memory at every request. We are still evaluating if memory management must be managed in the jvm plugin, or in the jwsgi one.
* Threading will be a core component of the JVM plugin in the future. Expect an update soon.
134 changes: 134 additions & 0 deletions Lua.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
Using Lua/WSAPI with uWSGI
==========================

Compilation notes
-----------------

Before compiling the plugin take a look at the :file:`plugins/lua/uwsgiplugin.py` configuration file. If you have installed Lua in some exotic directory you may need to adjust the ``CFLAGS`` and ``LIBS`` values.

For example, on a Debian/Ubuntu system you should use something like this:

.. code-block:: python
import os, sys
NAME='lua'
CFLAGS = ['-I/usr/include/lua5.1/']
LDFLAGS = []
GCC_LIST = ['lua_plugin']
LIBS = ['-llua5.1']
The ``lua.ini`` buildconf will build uWSGI with embedded Lua support. The ``luap.ini`` buildconf will build Lua support as a plugin.

.. code-block:: sh
python uwsgiconfig.py --build lua # embedded
python uwsgiconfig.py --build luap # plugin
# if you have already build the uWSGI core with the default config file...
python uwsgiconfig.py --plugin plugins/lua
# or if you have used another config file (for example core.ini)
python uwsgiconfig.py --plugin plugins/lua core
Your first WSAPI application
----------------------------

We will use the official WSAPI example, let's call it :file:`pippo.lua`:

.. code-block:: lua
function hello(wsapi_env)
local headers = { ["Content-type"] = "text/html" }
local function hello_text()
coroutine.yield("<html><body>")
coroutine.yield("<p>Hello Wsapi!</p>")
coroutine.yield("<p>PATH_INFO: " .. wsapi_env.PATH_INFO .. "</p>")
coroutine.yield("<p>SCRIPT_NAME: " .. wsapi_env.SCRIPT_NAME .. "</p>")
coroutine.yield("</body></html>")
end
return 200, headers, coroutine.wrap(hello_text)
end
return hello
Now run uWSGI with the ``lua`` option (remember to add ``--plugins lua`` as the first command line option if you are using it as a plugin)

.. code-block:: sh
./uwsgi -s :3031 -M -p 4 --lua pippo.lua -m
The Lua plugin's official uwsgi protocol modifier number is ``6``, so remember to set it in your web server configuration with the ``uWSGIModifier1``/``uwsgi_modifier1`` directive.

Abusing coroutines
------------------

One of the most exciting feature of Lua is coroutine (cooperative multithreading) support. uWSGI can benefit from this using its async core.

The Lua plugin will initialize a ``lua_State`` for every async core.

We will use a CPU-bound version of our pippo.lua to test it:

.. code-block:: lua
function hello(wsapi_env)
local headers = { ["Content-type"] = "text/html" }
local function hello_text()
coroutine.yield("<html><body>")
coroutine.yield("<p>Hello Wsapi!</p>")
coroutine.yield("<p>PATH_INFO: " .. wsapi_env.PATH_INFO .. "</p>")
coroutine.yield("<p>SCRIPT_NAME: " .. wsapi_env.SCRIPT_NAME .. "</p>")
for i=0, 10000, 1 do
coroutine.yield(i .. "<br/>")
end
coroutine.yield("</body></html>")
end
return 200, headers, coroutine.wrap(hello_text)
end
return hello
and run uWSGI with 8 async cores...

.. code-block:: sh
./uwsgi -s :3031 -M -p 4 --lua pippo.lua -m --async 8
And just like that, you can manage 8 concurrent requests within a single worker!

Threading
---------

The Lua plugin is "thread-safe" as uWSGI maps a lua_State to each internal pthread.

For example you can run the Sputnik_ wiki engine very easily.

Use LuaRocks_ to install Sputnik and ``versium-sqlite3``. A database-backed storage is required as the default filesystem storage does not support being accessed by multiple interpreters concurrently.

Create a wsapi compliant file:

.. code-block:: lua
require('sputnik')
return sputnik.wsapi_app.new{
VERSIUM_STORAGE_MODULE = "versium.sqlite3",
VERSIUM_PARAMS = {'/tmp/sputnik.db'},
SHOW_STACK_TRACE = true,
TOKEN_SALT = 'xxx',
BASE_URL = '/',
}
And run your threaded uWSGI server

..code-block:: sh

./uwsgi --plugins lua --lua sputnik.ws --threads 20 -s :3031

.. _Sputnik: http://sputnik.freewisdom.org/
.. _LuaRocks: http://www.luarocks.org/

A note on memory
----------------

As we all know, uWSGI is... fascist about memory. Memory is a precious resource. Do not trust software that does not care for your memory!
The Lua garbage collector is automatically called after each request. An option to set the frequency at which the GC runs will be available soon.
17 changes: 17 additions & 0 deletions Nagios.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Monitoring uWSGI with Nagios
============================

The official uWSGI distribution includes a plugin adding Nagios_ friendly output.

To monitor, and eventually get warning messages, via Nagios, launch the following command, Where ``node`` is the socket (UNIX or TCP) to monitor.

.. code-block:: sh
uwsgi --socket <node> --nagios
Setting warning messages
------------------------

You can set a warning message directly from your app with the :func:`uwsgi.set_warning_message` function. All the ping responses (used by Nagios too) will report this message.

.. _Nagios: http://www.nagios.com/
2 changes: 2 additions & 0 deletions Python.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ Python support
:maxdepth: 1

PythonModule
PythonDecorators
PythonPump
Tracebacker

.. seealso:: :ref:`Python configuration options <OptionsPython>`
Expand Down
Loading

0 comments on commit ca9b1c9

Please sign in to comment.