/cerbas

CERBAS ( Concurrent Elixir/Erlang Redis-backed API Server)

Primary LanguageElixirMIT LicenseMIT

CERBAS

Cerbas let languages other than elixir call functions written in elixir.

Cerbas uses redis as the "broker".

A client code, for example in python, prepares a json compatible request which stores in redis.

The json is fetched by cerbas server and routed to the configured elixir function.

The returned value from the function is serialized to a json response that is dispatched to the client by means of redis' publish capability.

Client -> json-request -> cerbas driver -> redis -> listen in channel X

Cerbas Server read incoming requests and dispatches to configured elixir functions, publish result to channel X.

To run cerbas install and ...

run redis...

$ redis-server

Open other terminal window and install elixir 1.4

and ...

clone this repo

$ git clone https://github.com/batok/cerbas.git
$ cd cerbas
$ mix deps.get
$ mix run

Open other terminal window and install python's stuff...

$ cd cerbas
$ python3 -m venv py3env
$ source py3env/bin/activate
$ pip install -r requirements.txt

and run the python example...

$ python3 cerbastest.py 

cerbastest.py make some requests to redis, which are routed to elixir functions by CERBAS Server.

the last request "halt" will stop CERBAS Server.

==================================================================

Cerbas can:

  • handle a timeout for executing functions ( default to 5 seconds).

  • compress published responses with msgpack ( optional ).

  • cache values for specific functions.

  • run scheduled functions by means of a CRON compatible file.

Use cases:

  • Scripts or code from any language which at some point need call one or more functions developed with elixir/erlang.

  • CRON like execution of elixir functions

Plus:

Cerbas includes a Plug Web Server which also serve as proxy to other web apps. Four examples are included.

To run the tornado app ...

$ python3 tornadoapp.py

Open any browser and go to localhost:4455/api7/foo

Cerbas' plug server will receive the http request and will route it to tornado web app.

===

The language must communicate with redis and serialize to and from a json like structure. Both are pretty supported in any language. The only caveat is that the redis communication must support "subscribe".

Currently only a python driver for cerbas is included but write an specific driver for any other language is easy if follow these:

Client - Server interaction using CERBAS.

1 - Client prepares a request which is json data containing:

{“func”: “name of an alias name to a real function”, “args”:
json_object_containg_arguments_if_any, “user”: “registered user name”, “source”: “kind of program where the request is generated, i.e. ror which is also registered”}

Example 1:

{“func”: “s3backup”, “args”: {}, “user”: “tom”, “source”: “flask_app”}

Example 2 ( with parameters ):

{“func”: “tablecount”, “args”: {“table”: “users”, “database”, “awesomedb”}, “user”: “peter”, “source”: “ror” }  

Example 3 ( with delay in milliseconds before running the task or function ):

{“func”: “send_a_notification_in_a_minute”, “args”: {}, “user”: “alice”, source:”django_app”, delay= 60000} 

2 - Steps done by any client in any language connected to redis ( db = 1 [dev], db = 8 [prod]).

A - INCR CERBAS_COUNTER

B - GET CERBAS_COUNTER

C - Key name is built this way:

CERBAS-REQ-[Value of CERBAS_COUNTER zero filled right justified to ten digits]

Example:

CERBAS-REQ-0000000001

D - SET Key as in "C" with the value of serialized json request ( see previous examples ).

E - RPUSH CERBAS_QUEUE [ with CERBAS_COUNTER contents, i.e. 1 ]

F - If the request doesn’t expect an answer from CERBAS that was it.

G - Redis pub-sub channel name built this way:

CERBAS-RESPONSE-[Value of number of redis db (1 for dev or 8 for production)]-[Value of CERBAS_COUNTER zero filled right justified to ten digits]

Example:

CERBAS-RESPONSE-1-0000000001

H - Client subscribe to this channel waiting for a response from CERBAS ( Server will publish the response to this channel when finishes processing the request ).

I - Response has the following json structure

{“status”: “ok”, “data”: json_value_or_structure_containing_result} when ok {“status”: “error”, “data”: “error message” } when having errors.

What CERBAS server does is reading values from the queue (LPOP) , (GET) ing the value of the key formed with the popped value, deleting the original request ( DELETE) and routing the request to a real elixir function which must return the possible values:

json value can be any poison serializable content

{:error,error message}

CERBAS will intercept this value an build the appropriate json response that will publish using the right channel in two forms: raw and compressed via msgpack. If the content was msgpacked the channel name used will be prefixed by MSGPACK:.

Due to concurrent goodies of the erlang vm every request is dispatched in its own process without conflicting or waiting for previous requests.