CloudI: A Cloud at the lowest level
Description: Cloud Framework for fault-tolerant distributed processing with dynamic load balancing
Keywords: cloud, private cloud, framework, erlang, fault tolerant, distributed systems, embarrassingly parallel, divide and conquer, cloudi

CloudI
A Cloud at the lowest level!

## Purpose

CloudI provides a Cloud for software developers without requiring virtualization.

## Usage

CloudI is for back-end server processing tasks that require soft-realtime transaction processing external to database usage (in ATS, C/C++, Erlang/Elixir, Go, Haskell, Java, JavaScript/node.js, OCaml, Perl, PHP, Python and Ruby). Examples include:

- REST API Implementation
- Account Management
- Authentication
- Game Server Development
- Data Mining
- Iterative Algorithms
- Protocol Implementation
- Telecommunications
- etc.

## Quick Start

C

1. A CloudI service written in C is called an "external" service because the service is ran inside an Operating System process (external to the Erlang VM). The example C service can be created by executing the following inside your shell:

       cat << EOF > hello_world.c
       #include "cloudi.h"
       #include <string.h>
       #include <assert.h>
       static void hello_world(int const request_type,
                               char const * const name,
                               char const * const pattern,
                               void const * const request_info,
                               uint32_t const request_info_size,
                               void const * const request,
                               uint32_t const request_size,
                               uint32_t timeout,
                               int8_t priority,
                               char const * const trans_id,
                               char const * const pid,
                               uint32_t const pid_size,
                               void * state,
                               cloudi_instance_t * api)
       {
           char const * const message = "Hello World!";
           uint32_t const message_size = strlen(message);
           cloudi_return(api, request_type, name, pattern, "", 0,
                         message, message_size,
                         timeout, trans_id, pid, pid_size);
       }
       int main(int argc, char ** argv)
       {
           unsigned int thread_count;
           int result = cloudi_initialize_thread_count(&thread_count);
           assert(result == cloudi_success);
           assert(thread_count == 1);
           cloudi_instance_t api;
           result = cloudi_initialize(&api, 0, 0);
           assert(result == cloudi_success);
           result = cloudi_subscribe(&api, "hello_world/get",
                                     &hello_world);
           assert(result == cloudi_success);
           result = cloudi_poll(&api, -1);
           cloudi_destroy(&api);
           return result;
       }
       EOF

2. Compile the CloudI service executable:

       gcc -I/usr/local/lib/cloudi-2.0.4/api/c \
           -L/usr/local/lib/cloudi-2.0.4/api/c \
           -g -O0 -fexceptions hello_world.c -o hello_world_c -lcloudi

3. Now it is necessary to create the CloudI service configuration that specifies both the initialization and fault-tolerance constraints the CloudI service should be executed with (with the proplist format to rely on defaults):

       export PWD=`pwd`
       cat << EOF > hello_world.conf
       [[{prefix, "/quickstart/c/"},
         {file_path, "$PWD/hello_world_c"},
         {env, [{"LD_LIBRARY_PATH",
                 "/usr/local/lib/cloudi-2.0.4/api/c/"},
                {"DYLD_LIBRARY_PATH",
                 "/usr/local/lib/cloudi-2.0.4/api/c/"}]}]]
       EOF

4. To dynamically add the CloudI service configuration that starts the service's execution use:

       curl -X POST -d @hello_world.conf \
           http://localhost:6464/cloudi/api/rpc/services_add.erl

5. The curl requests have been using the cowboy HTTP server that is running within the default CloudI configuration to allow the CloudI Service API to be used over HTTP. The same HTTP server can be used to make a CloudI service request to the hello_world service with:

       curl http://localhost:6464/quickstart/c/hello_world

6. If there was a problem during the service creation there would be an ERROR entry within the /usr/local/var/log/cloudi/cloudi.log file. If an error occurred with a curl command it would be displayed in the shell. The available service configuration parameters are described in the services_add documentation. More complex C examples are listed here.

C++

1. A CloudI service written in C++ is called an "external" service because the service is ran inside an Operating System process (external to the Erlang VM). The example C++ service can be created by executing the following inside your shell:

       cat << EOF > hello_world.cpp
       #include "cloudi.hpp"
       #include <string>
       #include <cassert>
       class Task
       {
           public:
               Task(unsigned int const thread_index) :
                   m_api(thread_index)
               {
                   int result = 0;
                   result = m_api.subscribe("hello_world/get",
                                            *this, &Task::hello_world);
                   assert(result == CloudI::API::return_value::success);
               }

               int run()
               {
                   return m_api.poll();
               }
           private:
               void hello_world(CloudI::API const & api,
                                int const request_type,
                                std::string const & name,
                                std::string const & pattern,
                                void const * const /*request_info*/,
                                uint32_t const /*request_info_size*/,
                                void const * const request,
                                uint32_t const request_size,
                                uint32_t timeout,
                                int8_t /*priority*/,
                                char const * const trans_id,
                                char const * const pid,
                                uint32_t const pid_size)
               {
                   std::string message("Hello World!");
                   api.return_(request_type, name, pattern, "", 0,
                               message.c_str(), message.size(),
                               timeout, trans_id, pid, pid_size);
               }
               CloudI::API m_api;
       };
       int main(int, char **)
       {
           unsigned int const thread_count = CloudI::API::thread_count();
           assert(thread_count == 1);
           Task t(0);
           return t.run();
       }
       EOF

2. Compile the CloudI service executable:

       g++ -I/usr/local/lib/cloudi-2.0.4/api/c \
           -L/usr/local/lib/cloudi-2.0.4/api/c \
           -g -O0 hello_world.cpp -o hello_world_cxx -lcloudi

3. Now it is necessary to create the CloudI service configuration that specifies both the initialization and fault-tolerance constraints the CloudI service should be executed with (with the proplist format to rely on defaults):

       export PWD=`pwd`
       cat << EOF > hello_world.conf
       [[{prefix, "/quickstart/cxx/"},
         {file_path, "$PWD/hello_world_cxx"},
         {env, [{"LD_LIBRARY_PATH",
                 "/usr/local/lib/cloudi-2.0.4/api/c/"},
                {"DYLD_LIBRARY_PATH",
                 "/usr/local/lib/cloudi-2.0.4/api/c/"}]}]]
       EOF

4. To dynamically add the CloudI service configuration that starts the service's execution use:

       curl -X POST -d @hello_world.conf \
           http://localhost:6464/cloudi/api/rpc/services_add.erl

5. The curl requests have been using the cowboy HTTP server that is running within the default CloudI configuration to allow the CloudI Service API to be used over HTTP. The same HTTP server can be used to make a CloudI service request to the hello_world service with:

       curl http://localhost:6464/quickstart/cxx/hello_world

6. If there was a problem during the service creation there would be an ERROR entry within the /usr/local/var/log/cloudi/cloudi.log file. If an error occurred with a curl command it would be displayed in the shell. The available service configuration parameters are described in the services_add documentation. More complex C++ examples are listed here.

Elixir

1. A CloudI service written in Elixir is called an "internal" service because the service is ran inside the Erlang VM. The example Elixir service can be created by executing the following inside your shell:

       mkdir lib
       cat << EOF > lib/HelloWorld.ex
       defmodule HelloWorld do

           import CloudILogger

           def cloudi_service_init(_args, _prefix, _timeout,
                                   dispatcher) do
               :cloudi_service.subscribe(dispatcher, 'hello_world/get')
               {:ok, :undefined}
           end

           def cloudi_service_handle_request(_request_type,
                                             _name, _pattern,
                                             _request_info, _request,
                                             _timeout, _priority,
                                             _transid, _pid, state,
                                             _dispatcher) do
               {:reply, "Hello World!", state}
           end

           def cloudi_service_handle_info(request, state, _dispatcher) do
               log_warn('Unknown info "~p"', [request])
               {:noreply, state}
           end

           def cloudi_service_terminate(_reason, _timeout, _state) do
               :ok
           end
       end
       EOF
       cat << EOF > mix.exs
       defmodule HelloWorld.Mixfile do
           use Mix.Project

           def project do
               [app: :'Elixir.HelloWorld',
                version: "2.0.4",
                elixirc_paths: ["lib/"],
                deps: []]
           end

           def application do
               [applications: [:cloudi_core]]
           end
       end
       EOF

2. Now compile the CloudI service module. If the CloudI service needed to utilize other Elixir dependencies they would be added to the mix.exs file.

       mix compile

3. You now have a CloudI service contained within a single Elixir module that may look familiar if you remember how a GenServer behavior works. Instead of using the GenServer behavior, we are using a cloudi_service behavior which provides more features with CloudI service requests. To allow the Erlang VM to find the CloudI service Elixir module that has been compiled, it is necessary to add the current directory to the code path:

       export PWD=`pwd`
       curl -X POST -d '"'$PWD'/_build/dev/lib/Elixir.HelloWorld/ebin"' \
           http://localhost:6464/cloudi/api/rpc/code_path_add.erl

4. If Elixir isn't already in the Erlang VM code search path, add it:

       curl -X POST -d '"/usr/local/lib/elixir/lib/elixir/ebin"' \
           http://localhost:6464/cloudi/api/rpc/code_path_add.erl

5. Now it is necessary to create the CloudI service configuration that specifies both the initialization and fault-tolerance constraints the CloudI service should be executed with (with the proplist format to rely on defaults):

       cat << EOF > hello_world.conf
       [[{prefix, "/quickstart/elixir/"},
         {module, 'Elixir.HelloWorld'}]]
       EOF

6. To dynamically add the CloudI service configuration that starts the service's execution use:

       curl -X POST -d @hello_world.conf \
           http://localhost:6464/cloudi/api/rpc/services_add.erl

7. The curl requests have been using the cowboy HTTP server that is running within the default CloudI configuration to allow the CloudI Service API to be used over HTTP. The same HTTP server can be used to make a CloudI service request to the hello_world service with:

       curl http://localhost:6464/quickstart/elixir/hello_world

8. If there was a problem during the service creation there would be an ERROR entry within the /usr/local/var/log/cloudi/cloudi.log file. If an error occurred with a curl command it would be displayed in the shell. The available service configuration parameters are described in the services_add documentation.

Erlang

1. A CloudI service written in Erlang (or using a language based on core Erlang like Elixir) is called an "internal" service because the service is ran inside the Erlang VM. The example Erlang service can be created by executing the following inside your shell:

       cat << EOF > hello_world.erl
       -module(hello_world).
       -behaviour(cloudi_service).

       %% cloudi_service callbacks
       -export([cloudi_service_init/4,
                cloudi_service_handle_request/11,
                cloudi_service_handle_info/3,
                cloudi_service_terminate/3]).

       -include_lib("cloudi_core/include/cloudi_logger.hrl").

       -record(state,
           {
           }).

       cloudi_service_init(_Args, _Prefix, _Timeout, Dispatcher) ->
           cloudi_service:subscribe(Dispatcher, "hello_world/get"),
           {ok, #state{}}.

       cloudi_service_handle_request(_RequestType, _Name, _Pattern,
                                     _RequestInfo, _Request,
                                     _Timeout, _Priority,
                                     _TransId, _Pid,
                                     #state{} = State, _Dispatcher) ->
           {reply, <<"Hello World!">>, State}.

       cloudi_service_handle_info(Request, State, _Dispatcher) ->
           ?LOG_WARN("Unknown info \"~p\"", [Request]),
           {noreply, State}.

       cloudi_service_terminate(_Reason, _Timeout, #state{}) ->
           ok.
       EOF

2. Now compile the CloudI service module. If the CloudI service needed to utilize other Erlang dependencies an Erlang/OTP .app file would be added with the same filename (see the examples for more details).

       erlc -pz /usr/local/lib/cloudi-2.0.4/lib/cloudi_core-2.0.4/ebin \
           hello_world.erl

3. You now have a CloudI service contained within a single Erlang module that may look familiar if you remember how a gen_server behavior works. Instead of using the gen_server behavior, we are using a cloudi_service behavior which provides more features with CloudI service requests. To allow the Erlang VM to find the CloudI service Erlang module that has been compiled, it is necessary to add the current directory to the code path:

       curl -X POST -d '"'`pwd`'"' \
           http://localhost:6464/cloudi/api/rpc/code_path_add.erl

4. Now it is necessary to create the CloudI service configuration that specifies both the initialization and fault-tolerance constraints the CloudI service should be executed with (with the proplist format to rely on defaults):

       cat << EOF > hello_world.conf
       [[{prefix, "/quickstart/erlang/"},
         {module, hello_world}]]
       EOF

5. To dynamically add the CloudI service configuration that starts the service's execution use:

       curl -X POST -d @hello_world.conf \
           http://localhost:6464/cloudi/api/rpc/services_add.erl

6. The curl requests have been using the cowboy HTTP server that is running within the default CloudI configuration to allow the CloudI Service API to be used over HTTP. The same HTTP server can be used to make a CloudI service request to the hello_world service with:

       curl http://localhost:6464/quickstart/erlang/hello_world

7. If there was a problem during the service creation there would be an ERROR entry within the /usr/local/var/log/cloudi/cloudi.log file. If an error occurred with a curl command it would be displayed in the shell. To get more details on CloudI Erlang integration (i.e., CloudI runtime usage with Erlang) see the examples in the source code repository. The available service configuration parameters are described in the services_add documentation. More complex Erlang examples are listed here.

Go

1. CloudI must be compiled and installed after using the configure argument "--enable-go-support" before attempting the Go quickstart below:
2. A CloudI service written in Go is called an "external" service because the service is ran inside an Operating System process (external to the Erlang VM). The example Go service can be created by executing the following inside your shell:

       cat << EOF > go.mod
       module hello_world_go

       replace (
           github.com/CloudI/cloudi_api_go/v2/cloudi => /usr/local/lib/cloudi-2.0.4/api/go/cloudi
           github.com/okeuday/erlang_go/v2/erlang => /usr/local/lib/cloudi-2.0.4/api/go/erlang
       )

       require (
           github.com/CloudI/cloudi_api_go/v2/cloudi v0.0.0-00000000000000-000000000000
           github.com/okeuday/erlang_go/v2/erlang v0.0.0-00000000000000-000000000000
       )
       EOF
       cat << EOF > main.go
       package main

       import (
           "github.com/CloudI/cloudi_api_go/v2/cloudi"
           "os"
           "sync"
       )

       func helloWorld(requestType int, name, pattern string, requestInfo, request []byte, timeout uint32, priority int8, transId [16]byte, pid cloudi.Source, state interface{}, api *cloudi.Instance) ([]byte, []byte, error) {
           return nil, []byte("Hello World!"), nil
       }

       func task(threadIndex uint32, execution *sync.WaitGroup) {
           defer execution.Done()
           api, err := cloudi.API(threadIndex, nil)
           if err != nil {
               cloudi.ErrorWrite(os.Stderr, err)
               return
           }
           err = api.Subscribe("hello_world/get", helloWorld)
           if err != nil {
               cloudi.ErrorWrite(os.Stderr, err)
               return
           }
           _, err = api.Poll(-1)
           if err != nil {
               cloudi.ErrorWrite(os.Stderr, err)
           }
       }

       func main() {
           threadCount, err := cloudi.ThreadCount()
           if err != nil {
               cloudi.ErrorExit(os.Stderr, err)
           }
           var execution sync.WaitGroup
           for threadIndex := uint32(0); threadIndex < threadCount; threadIndex++ {
               execution.Add(1)
               go task(threadIndex, &execution)
           }
           execution.Wait()
       }
       EOF

3. Compile the CloudI service executable:

       GOBIN=`pwd` go install -x hello_world_go

4. Now it is necessary to create the CloudI service configuration that specifies both the initialization and fault-tolerance constraints the CloudI service should be executed with (with the proplist format to rely on defaults):

       export PWD=`pwd`
       cat << EOF > hello_world.conf
       [[{prefix, "/quickstart/go/"},
         {file_path, "$PWD/hello_world_go"}]]
       EOF

5. To dynamically add the CloudI service configuration that starts the service's execution use:

       curl -X POST -d @hello_world.conf \
           http://localhost:6464/cloudi/api/rpc/services_add.erl

6. The curl requests have been using the cowboy HTTP server that is running within the default CloudI configuration to allow the CloudI Service API to be used over HTTP. The same HTTP server can be used to make a CloudI service request to the hello_world service with:

       curl http://localhost:6464/quickstart/go/hello_world

7. If there was a problem during the service creation there would be an ERROR entry within the /usr/local/var/log/cloudi/cloudi.log file. If an error occurred with a curl command it would be displayed in the shell. The available service configuration parameters are described in the services_add documentation. More complex Go examples are listed here.

Java

1. A CloudI service written in Java is called an "external" service because the service is ran inside an Operating System process (external to the Erlang VM). The example Java service can be created by executing the following inside your shell:

       mkdir -p org/cloudi/tests/hello_world/
       cat << EOF > org/cloudi/tests/hello_world/Main.java
       package org.cloudi.tests.hello_world;

       import org.cloudi.API;

       public class Main
       {
           public static void main(String[] args)
           {
               try
               {
                   final int thread_count = API.thread_count();
                   assert(thread_count == 1);
                   Task t = new Task(0);
                   t.run();
               }
               catch (API.InvalidInputException e)
               {
                   e.printStackTrace(API.err);
               }
           }
       }
       EOF
       cat << EOF > org/cloudi/tests/hello_world/Task.java
       package org.cloudi.tests.hello_world;

       import com.ericsson.otp.erlang.OtpErlangPid;
       import org.cloudi.API;

       public class Task
       {
           private API api;

           public Task(final int thread_index)
           {
               try
               {
                   this.api = new API(thread_index);
               }
               catch (API.InvalidInputException e)
               {
                   e.printStackTrace(API.err);
                   System.exit(1);
               }
               catch (API.MessageDecodingException e)
               {
                   e.printStackTrace(API.err);
                   System.exit(1);
               }
               catch (API.TerminateException e)
               {
                   System.exit(1);
               }
           }

           public Object hello_world(Integer request_type,
                                     String name, String pattern,
                                     byte[] request_info,
                                     byte[] request,
                                     Integer timeout, Byte priority,
                                     byte[] trans_id, OtpErlangPid pid)
           {
               return ("Hello World!").getBytes();
           }

           public void run()
           {
               try
               {
                   this.api.subscribe("hello_world/get",
                                      this, "hello_world");
                   this.api.poll();
               }
               catch (API.TerminateException e)
               {
               }
               catch (Exception e)
               {
                   e.printStackTrace(API.err);
               }
           }
       }

       EOF
       cat << EOF > manifest.txt
       Main-Class: org.cloudi.tests.hello_world.Main
       Class-Path: /usr/local/lib/cloudi-2.0.4/api/java/cloudi.jar

       EOF

2. Compile the CloudI service jar:

       cd org/cloudi/tests/hello_world/
       CLASSPATH=/usr/local/lib/cloudi-2.0.4\
       /api/java/cloudi.jar:${CLASSPATH} javac Task.java Main.java
       cd ../../../../
       jar cvfm hello_world.jar manifest.txt org

3. Now it is necessary to create the CloudI service configuration that specifies both the initialization and fault-tolerance constraints the CloudI service should be executed with (with the proplist format to rely on defaults):

       export JAVA=`which java`
       export PWD=`pwd`
       cat << EOF > hello_world.conf
       [[{prefix, "/quickstart/java/"},
         {file_path, "$JAVA"},
         {args, "-cp /usr/local/lib/cloudi-2.0.4/api/java/ "
                "-ea:org.cloudi... -jar $PWD/hello_world.jar"}]]
       EOF

4. To dynamically add the CloudI service configuration that starts the service's execution use:

       curl -X POST -d @hello_world.conf \
           http://localhost:6464/cloudi/api/rpc/services_add.erl

5. The curl requests have been using the cowboy HTTP server that is running within the default CloudI configuration to allow the CloudI Service API to be used over HTTP. The same HTTP server can be used to make a CloudI service request to the hello_world service with:

       curl http://localhost:6464/quickstart/java/hello_world

6. If there was a problem during the service creation there would be an ERROR entry within the /usr/local/var/log/cloudi/cloudi.log file. If an error occurred with a curl command it would be displayed in the shell. The available service configuration parameters are described in the services_add documentation. More complex Java examples are listed here.

JavaScript

1. A CloudI service written in JavaScript is called an "external" service because the service is ran inside an Operating System process (external to the Erlang VM). The example JavaScript service can be created by executing the following inside your shell:

       cat << EOF > hello_world.js
       var CloudI = require('/usr/local/lib/cloudi-2.0.4/' +
                            'api/javascript/CloudI.js').CloudI;
       var assert = require('assert');

       Task = function Task (thread_index) {
           var Task = this;
           Task._thread_index = thread_index;
       };
       Task.prototype.run = function () {
           var Task = this;
           try {
               new CloudI.API(Task._thread_index, function (api) {
               Task._api = api;
               Task._api.subscribe('hello_world/get', Task,
                                   Task.hello_world,
                                   function () {
               Task._api.poll(function (timeout) {
               });
               });});
           }
           catch (err) {
               if (typeof err.stack !== 'undefined') {
                   process.stderr.write(err.stack + '\n');
               }
               else {
                   process.stderr.write(err + '\n');
               }
           }
       };
       Task.prototype.hello_world = function (request_type, name, pattern,
                                              request_info, request,
                                              timeout, priority,
                                              trans_id, pid) {
           return 'Hello World!';
       };

       assert(CloudI.API.thread_count() == 1);
       var thread = new Task(0);
       thread.run();
       EOF

2. Now it is necessary to create the CloudI service configuration that specifies both the initialization and fault-tolerance constraints the CloudI service should be executed with (with the proplist format to rely on defaults):

       export NODE=`which node`
       export PWD=`pwd`
       cat << EOF > hello_world.conf
       [[{prefix, "/quickstart/javascript/"},
         {file_path, "$NODE"},
         {args, "$PWD/hello_world.js"}]]
       EOF

3. To dynamically add the CloudI service configuration that starts the service's execution use:

       curl -X POST -d @hello_world.conf \
           http://localhost:6464/cloudi/api/rpc/services_add.erl

4. The curl requests have been using the cowboy HTTP server that is running within the default CloudI configuration to allow the CloudI Service API to be used over HTTP. The same HTTP server can be used to make a CloudI service request to the hello_world service with:

       curl http://localhost:6464/quickstart/javascript/hello_world

5. If there was a problem during the service creation there would be an ERROR entry within the /usr/local/var/log/cloudi/cloudi.log file. If an error occurred with a curl command it would be displayed in the shell. The available service configuration parameters are described in the services_add documentation. More complex JavaScript examples are listed here.

Perl

1. A CloudI service written in Perl is called an "external" service because the service is ran inside an Operating System process (external to the Erlang VM). The example Perl service can be created by executing the following inside your shell:

       cat << EOF > hello_world.pl
       use strict;
       use warnings;

       require CloudI::API;
       require CloudI::TerminateException;

       sub task
       {
           my (\$api) = @_;
           eval
           {
               my \$task_hello_world = sub
               {
                   my (\$request_type, \$name, \$pattern,
                       \$request_info, \$request,
                       \$timeout, \$priority, \$trans_id, \$pid) = @_;
                   return 'Hello World!';
               };
               \$api->subscribe('hello_world/get', \$task_hello_world);
               \$api->poll();
           };
           my \$e = \$@;
           if (\$e)
           {
               if (\$e->isa('CloudI::TerminateException'))
               {
                   1;
               }
               else
               {
                   print "\$e";
               }
           }
       }
       {
           CloudI::API->assert(CloudI::API->thread_count() == 1);
           task(CloudI::API->new(0));
       }
       EOF

2. Now it is necessary to create the CloudI service configuration that specifies both the initialization and fault-tolerance constraints the CloudI service should be executed with (with the proplist format to rely on defaults):

       export PERL=`which perl`
       export PWD=`pwd`
       cat << EOF > hello_world.conf
       [[{prefix, "/quickstart/perl/"},
         {file_path, "$PERL"},
         {args, "$PWD/hello_world.pl"},
         {env, [{"PERL5LIB", "/usr/local/lib/cloudi-2.0.4/api/perl"}]}]]
       EOF

3. To dynamically add the CloudI service configuration that starts the service's execution use:

       curl -X POST -d @hello_world.conf \
           http://localhost:6464/cloudi/api/rpc/services_add.erl

4. The curl requests have been using the cowboy HTTP server that is running within the default CloudI configuration to allow the CloudI Service API to be used over HTTP. The same HTTP server can be used to make a CloudI service request to the hello_world service with:

       curl http://localhost:6464/quickstart/perl/hello_world

5. If there was a problem during the service creation there would be an ERROR entry within the /usr/local/var/log/cloudi/cloudi.log file. If an error occurred with a curl command it would be displayed in the shell. The available service configuration parameters are described in the services_add documentation. More complex Perl examples are listed here.

PHP

1. A CloudI service written in PHP is called an "external" service because the service is ran inside an Operating System process (external to the Erlang VM). The example PHP service can be created by executing the following inside your shell:

       cat << EOF > hello_world.php
       <?php

       require '/usr/local/lib/cloudi-2.0.4/api/php/CloudI.php';

       class Task
       {
           private \$api;

           public function __construct(\$api)
           {
               \$this->api = \$api;
           }

           public function run()
           {
               try
               {
                   \$this->api->subscribe('hello_world/get',
                                               \$this, 'hello_world');
                   \$this->api->poll();
               }
               catch (\CloudI\TerminateException \$e)
               {
               }
               catch (Exception \$e)
               {
                   error_log("{\$e->getMessage()}\n{\$e}\n");
               }
           }

           public function hello_world(\$request_type, \$name, \$pattern,
                                       \$request_info, \$request,
                                       \$timeout, \$priority,
                                       \$trans_id, \$pid)
           {
               return 'Hello World!';
           }
       }

       \$thread_count = \CloudI\API::thread_count();
       assert(\$thread_count == 1);
       \$main_thread = new Task(new \CloudI\API(0));
       \$main_thread->run();

       ?>
       EOF

2. Now it is necessary to create the CloudI service configuration that specifies both the initialization and fault-tolerance constraints the CloudI service should be executed with (with the proplist format to rely on defaults):

       export PHP=`which php`
       export PWD=`pwd`
       cat << EOF > hello_world.conf
       [[{prefix, "/quickstart/php/"},
         {file_path, "$PHP"},
         {args, "$PWD/hello_world.php"}]]
       EOF

3. To dynamically add the CloudI service configuration that starts the service's execution use:

       curl -X POST -d @hello_world.conf \
           http://localhost:6464/cloudi/api/rpc/services_add.erl

4. The curl requests have been using the cowboy HTTP server that is running within the default CloudI configuration to allow the CloudI Service API to be used over HTTP. The same HTTP server can be used to make a CloudI service request to the hello_world service with:

       curl http://localhost:6464/quickstart/php/hello_world

5. If there was a problem during the service creation there would be an ERROR entry within the /usr/local/var/log/cloudi/cloudi.log file. If an error occurred with a curl command it would be displayed in the shell. The available service configuration parameters are described in the services_add documentation. More complex PHP examples are listed here.

Python

1. A CloudI service written in Python is called an "external" service because the service is ran inside an Operating System process (external to the Erlang VM). The example Python service can be created by executing the following inside your shell:

       cat << EOF > hello_world.py
       import sys
       sys.path.append('/usr/local/lib/cloudi-2.0.4/api/python/')
       import traceback
       from cloudi import API, terminate_exception

       class Task(object):
           def __init__(self):
               self.__api = API(0) # first/only thread == 0

           def run(self):
               try:
                   self.__api.subscribe("hello_world/get",
                                        self.__hello_world)
                   self.__api.poll()
               except terminate_exception:
                   pass
               except:
                   traceback.print_exc(file=sys.stderr)

           def __hello_world(self, request_type, name, pattern,
                             request_info, request,
                             timeout, priority, trans_id, pid):
               return b'Hello World!'

       if __name__ == '__main__':
           assert API.thread_count() == 1
           task = Task()
           task.run()
       EOF

2. Now it is necessary to create the CloudI service configuration that specifies both the initialization and fault-tolerance constraints the CloudI service should be executed with (either python2 or python3 will work and the python executable name may instead be "python" on your system):

       export PYTHON=`which python3`
       export PWD=`pwd`
       cat << EOF > hello_world.conf
       [[{prefix, "/quickstart/python/"},
         {file_path, "$PYTHON"},
         {args, "$PWD/hello_world.py"}]]
       EOF

3. To dynamically add the CloudI service configuration that starts the service's execution use:

       curl -X POST -d @hello_world.conf \
           http://localhost:6464/cloudi/api/rpc/services_add.erl

4. The curl requests have been using the cowboy HTTP server that is running within the default CloudI configuration to allow the CloudI Service API to be used over HTTP. The same HTTP server can be used to make a CloudI service request to the hello_world service with:

       curl http://localhost:6464/quickstart/python/hello_world

5. If there was a problem during the service creation there would be an ERROR entry within the /usr/local/var/log/cloudi/cloudi.log file. If an error occurred with a curl command it would be displayed in the shell. The available service configuration parameters are described in the services_add documentation. More complex Python examples are listed here.

Ruby

1. A CloudI service written in Ruby is called an "external" service because the service is ran inside an Operating System process (external to the Erlang VM). The example Ruby service can be created by executing the following inside your shell:

       cat << EOF > hello_world.rb
       \$:.unshift '/usr/local/lib/cloudi-2.0.4/api/ruby'

       \$DEBUG = false

       require 'cloudi'

       if __FILE__ == \$PROGRAM_NAME
           thread_count = CloudI::API.thread_count()
           CloudI::API.assert{thread_count == 1}

           class Task
               def initialize(thread_index)
                   @api = CloudI::API.new(thread_index)
               end

               def run
                   begin
                       @api.subscribe('hello_world/get',
                                      method(:hello_world))

                       @api.poll
                   rescue CloudI::TerminateException
                       #
                   rescue
                       \$stderr.puts \$!.message
                       \$stderr.puts \$!.backtrace
                   end
               end

               private

               def hello_world(request_type, name, pattern,
                               request_info, request,
                               timeout, priority, trans_id, pid)
                   return 'Hello World!';
               end
           end
           begin
               object = Task.new(0)
               object.run
           rescue
               \$stderr.puts \$!.message
               \$stderr.puts \$!.backtrace
           end
       end
       EOF

2. Now it is necessary to create the CloudI service configuration that specifies both the initialization and fault-tolerance constraints the CloudI service should be executed with (with the proplist format to rely on defaults):

       export RUBY=`which ruby` # must be ≥ 1.9
       export PWD=`pwd`
       cat << EOF > hello_world.conf
       [[{prefix, "/quickstart/ruby/"},
         {file_path, "$RUBY"},
         {args, "$PWD/hello_world.rb"}]]
       EOF

3. To dynamically add the CloudI service configuration that starts the service's execution use:

       curl -X POST -d @hello_world.conf \
           http://localhost:6464/cloudi/api/rpc/services_add.erl

4. The curl requests have been using the cowboy HTTP server that is running within the default CloudI configuration to allow the CloudI Service API to be used over HTTP. The same HTTP server can be used to make a CloudI service request to the hello_world service with:

       curl http://localhost:6464/quickstart/ruby/hello_world

5. If there was a problem during the service creation there would be an ERROR entry within the /usr/local/var/log/cloudi/cloudi.log file. If an error occurred with a curl command it would be displayed in the shell. The available service configuration parameters are described in the services_add documentation. More complex Ruby examples are listed here.

1. Get wget and curl if you don't already have them
   - (Ubuntu) sudo apt-get install wget curl
   - (OSX) sudo port install wget curl
2. Get CloudI running (need ./configure help?):

       wget https://osdn.net/dl/cloudi/cloudi-2.0.4.tar.gz

       tar zxvf cloudi-2.0.4.tar.gz

       cd cloudi-2.0.4/src

       ./configure

       make

       sudo make install

       cd ../..

       sudo cloudi start

3. The CloudI integration tests are now running and consuming your available CPUs. The /usr/local/var/log/cloudi/cloudi.log file provides integration test output. You can now select a programming language above to create a CloudI service.