|
|
# Introduction
|
|
|
The first goal of Cameo is to provide services for starting, stopping, synchronizing remote applications. The control of the lifecycle of the applications is made either by the console i.e. *cmo* either programmatically using the API. Here are the controls:
|
|
|
* **Start**: Starts a remote application that will run on the contacted Cameo server. The application must be registered.
|
|
|
The first goal of CAMEO is to provide services for starting, stopping, synchronizing remote applications. The control of the lifecycle of the applications is made either by the console i.e. *cmo* either programmatically using the API. Here are the controls:
|
|
|
* **Start**: Starts a remote application that will run on the contacted CAMEO server. The application must be registered.
|
|
|
* **Stop**: Stops a running remote application. The application is notified and can properly stop.
|
|
|
* **Kill**: Kills a running remote application. The application is immediately terminated.
|
|
|
* **Connect**: Connects a running application.
|
... | ... | @@ -8,24 +8,24 @@ The combination of these controls gives lots of flexibility e.g. applications ca |
|
|
|
|
|
# State diagram of an app
|
|
|
|
|
|
Every control is made by contacting the Cameo server which is responsible to control the applications. Every Cameo application has a sequence of states. The following diagram shows the complete possibilities:
|
|
|
Every control is made by contacting the CAMEO server which is responsible to control the applications. Every Cameo application has a sequence of states. The following diagram shows the complete possibilities:
|
|
|
|
|
|
![Application States](images/Application-states.png)
|
|
|
|
|
|
The arrows show which transitions are possible.
|
|
|
|
|
|
The different states are described:
|
|
|
* **Starting**: Once the Cameo server received a *start* request for a valid application.
|
|
|
* **Starting**: Once the CAMEO server received a *start* request for a valid application.
|
|
|
* **Running**: The application becomes *Running* after a defined amount of time or the application defined itself as running.
|
|
|
* **Success**: The application successfully terminated without any *stop* or *kill* request.
|
|
|
* **Stopping**: Once the Cameo server received a *stop* request for a running application.
|
|
|
* **Stopping**: Once the CAMEO server received a *stop* request for a running application.
|
|
|
* **Stopped**: The application successfully terminated after a *stop* request.
|
|
|
* **Killing**: Once the Cameo server received a *kill* request for a running application.
|
|
|
* **Killing**: Once the CAMEO server received a *kill* request for a running application.
|
|
|
* **Killed**: The application successfully terminated after a *kill* request.
|
|
|
* **Processing Failure**: Once the application encountered an internal error and terminated. An error process specific to the application is called.
|
|
|
* **Failure**: The error process has terminated.
|
|
|
|
|
|
Once the Cameo server is changing the state of an application, it also publishes the new state as an event. All the connected clients receive the new state and can react to it.
|
|
|
Once the CAMEO server is changing the state of an application, it also publishes the new state as an event. All the connected clients receive the new state and can react to it.
|
|
|
|
|
|
# Events in the API and the console
|
|
|
|
... | ... | @@ -34,10 +34,10 @@ Let's take a concrete example and show how to do it with the API and the console |
|
|
![Control the apps](images/Control-the-apps.png)
|
|
|
|
|
|
Sequence of actions:
|
|
|
* The application *App1* on *A* is contacting the Cameo server on *B* to start *App2*.
|
|
|
* The application *App1* on *A* is contacting the CAMEO server on *B* to start *App2*.
|
|
|
* The application *App2* is running on *B*.
|
|
|
* The application *App3* on *C* is contacting the Cameo server on *B* to connect *App2*.
|
|
|
* The console on *D* is contacting the Cameo server on *B* to connect *App2*.
|
|
|
* The application *App3* on *C* is contacting the CAMEO server on *B* to connect *App2*.
|
|
|
* The console on *D* is contacting the CAMEO server on *B* to connect *App2*.
|
|
|
* The application *App3* on *C* stops *App2*.
|
|
|
* The application *App1* and console are notified that *App2* stopped.
|
|
|
|
... | ... | @@ -50,7 +50,7 @@ public class JavaApp { |
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
// Initialize the Cameo application represented by This.
|
|
|
// Initialize the CAMEO application represented by This.
|
|
|
This.init(args);
|
|
|
|
|
|
// Infinite printing loop.
|
... | ... | @@ -70,7 +70,7 @@ public class JavaApp { |
|
|
}
|
|
|
```
|
|
|
|
|
|
It simply prints a new line every 100 ms infinitely. Notice that the name "App2" is the name of the application registered in the Cameo server so that there is no link with the class name.
|
|
|
It simply prints a new line every 100 ms infinitely. Notice that the name "App2" is the name of the application registered in the CAMEO server so that there is no link with the class name.
|
|
|
Moreover consider that the app is registered so that its standard output and error are streamed.
|
|
|
|
|
|
The application *App1* written in C++ has the following lines:
|
... | ... | @@ -81,7 +81,7 @@ The application *App1* written in C++ has the following lines: |
|
|
|
|
|
int main(int argc, char *argv[]) {
|
|
|
|
|
|
// Define the reference to the Cameo server in B.
|
|
|
// Define the reference to the CAMEO server in B.
|
|
|
std::unique_ptr<cameo::Server> server = cameo::Server::create("tcp://B:7000");
|
|
|
|
|
|
// Initialize the server.
|
... | ... | @@ -101,14 +101,14 @@ int main(int argc, char *argv[]) { |
|
|
}
|
|
|
```
|
|
|
|
|
|
It simply contacts the Cameo server in B and starts *App2* then waits for its termination.
|
|
|
It simply contacts the CAMEO server in B and starts *App2* then waits for its termination.
|
|
|
|
|
|
The application *App3* written in Python has the following lines:
|
|
|
|
|
|
```python
|
|
|
import cameopy
|
|
|
|
|
|
# Define the reference to the Cameo server in B.
|
|
|
# Define the reference to the CAMEO server in B.
|
|
|
server = cameopy.Server.create("tcp://B:7000")
|
|
|
|
|
|
# Initialize the server.
|
... | ... | @@ -140,11 +140,11 @@ The application App2.5 terminated successfully. |
|
|
|
|
|
The lines starting with *Connected* and *The application* are written by the console whereas the lines starting with *Printing* come from the app itself as it was configured to stream its error and output.
|
|
|
|
|
|
The calls to *waitFor()* were blocking and the termination of *App2* unblocked them as an event was sent from the Cameo server to all the clients. The console received the error and output stream before stopping, the *connect* command being blocking.
|
|
|
The calls to *waitFor()* were blocking and the termination of *App2* unblocked them as an event was sent from the CAMEO server to all the clients. The console received the error and output stream before stopping, the *connect* command being blocking.
|
|
|
|
|
|
# Using the console
|
|
|
|
|
|
The console *cmo* offers interesting features to start or monitor a Cameo environment. To print the help:
|
|
|
The console *cmo* offers interesting features to start or monitor a CAMEO environment. To print the help:
|
|
|
```
|
|
|
$ cmo
|
|
|
```
|
... | ... | @@ -154,13 +154,13 @@ To display the list of registered apps that can be started: |
|
|
$ cmo list
|
|
|
```
|
|
|
|
|
|
By default, the Cameo server is the local on the 7000 port but it can be configured.
|
|
|
If a Cameo server is running on the port 8000:
|
|
|
By default, the CAMEO server is the local on the 7000 port but it can be configured.
|
|
|
If a CAMEO server is running on the port 8000:
|
|
|
```
|
|
|
$ cmo -p 8000 list
|
|
|
```
|
|
|
|
|
|
If a Cameo server is running on *B*:
|
|
|
If a CAMEO server is running on *B*:
|
|
|
```
|
|
|
$ cmo -e tcp://B:7000 list
|
|
|
```
|
... | ... | @@ -178,7 +178,7 @@ Name ID PID Status Args |
|
|
App2 5 9087 RUNNING
|
|
|
```
|
|
|
|
|
|
The *ID* is the id of the Cameo server which is unique different from the *PID* which is the common system process id.
|
|
|
The *ID* is the id of the CAMEO server which is unique different from the *PID* which is the common system process id.
|
|
|
|
|
|
We can connect to it now:
|
|
|
```
|
... | ... | @@ -213,9 +213,9 @@ This time we typed *ctl+c* to kill the app. We could have used *shift+s* to clea |
|
|
|
|
|
Some additional commands and features can be interesting to know.
|
|
|
|
|
|
We saw that by default *cmo* contacts the local Cameo server on port 7000. You can change that by defining the *CAMEO_SERVER* environment variable e.g. with *tcp://localhost:8000* which can be useful if you configured the Cameo server with that port.
|
|
|
We saw that by default *cmo* contacts the local CAMEO server on port 7000. You can change that by defining the *CAMEO_SERVER* environment variable e.g. with *tcp://localhost:8000* which can be useful if you configured the Cameo server with that port.
|
|
|
|
|
|
You can display the Cameo server endpoint:
|
|
|
You can display the CAMEO server endpoint:
|
|
|
```
|
|
|
$ cmo endpoint
|
|
|
```
|
... | ... | @@ -260,8 +260,8 @@ cameo::State state = app->getActualState(); |
|
|
std::set<cameo::State> states = app->getPastStates();
|
|
|
```
|
|
|
|
|
|
The call to *getLastState()* does not invoke a call on the Cameo server but only pulls all the states already received. If the app has terminated then it should be *SUCCESS*, *STOPPED*, *KILLED* or *FAILURE*.
|
|
|
However a call to *getActualState()* makes a request to the Cameo server i.e. it can fail if the server is not accessible anymore.
|
|
|
The call to *getLastState()* does not invoke a call on the CAMEO server but only pulls all the states already received. If the app has terminated then it should be *SUCCESS*, *STOPPED*, *KILLED* or *FAILURE*.
|
|
|
However a call to *getActualState()* makes a request to the CAMEO server i.e. it can fail if the server is not accessible anymore.
|
|
|
|
|
|
# Exit code
|
|
|
|
... | ... | @@ -292,7 +292,7 @@ What you do with this code is on your own. |
|
|
|
|
|
# Stop handler
|
|
|
|
|
|
We saw before that there was a difference between a *stop* and a *kill* request. The Cameo server immediately stops the app for a *kill* request whereas in case of a *stop* request it sets the state *STOPPING* to the app. The app receives the *STOPPING* event and a stop handler is triggered if it has been registered allowing to properly terminate the app.
|
|
|
We saw before that there was a difference between a *stop* and a *kill* request. The CAMEO server immediately stops the app for a *kill* request whereas in case of a *stop* request it sets the state *STOPPING* to the app. The app receives the *STOPPING* event and a stop handler is triggered if it has been registered allowing to properly terminate the app.
|
|
|
|
|
|
The C++, Java and Python APIs support the stop handler. An example in C++:
|
|
|
```cpp
|
... | ... | @@ -406,7 +406,7 @@ public class JavaApp { |
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
|
|
// Initialize the Cameo application represented by This.
|
|
|
// Initialize the CAMEO application represented by This.
|
|
|
This.init(args);
|
|
|
|
|
|
// Get the starter app.
|
... | ... | @@ -546,7 +546,7 @@ Retrieving the output may not be only restricted to debug. If you need to integr |
|
|
|
|
|
# Unlinked apps
|
|
|
|
|
|
By default, if *App1* starts *App2* and *App1* finished before *App2* then *App2* will be stopped i.e. a stop request will be sent to its Cameo server. This default behaviour avoids to have orphaned apps that have in fact no reason to live especially if their starter app terminated unexpectedly.
|
|
|
By default, if *App1* starts *App2* and *App1* finished before *App2* then *App2* will be stopped i.e. a stop request will be sent to its CAMEO server. This default behaviour avoids to have orphaned apps that have in fact no reason to live especially if their starter app terminated unexpectedly.
|
|
|
|
|
|
However there are some cases where it is interesting to detach the lifecycle of an app from its starter. In that case, you simply have to specify it in the start command.
|
|
|
|
... | ... | |