Use blocking get call w/ timeout to read msg queue
Add parameters to the queue get method in the xapp_frame loop that reads
messages so it waits for a message to arrive and occasionally checks for
the end-loop flag, instead of spinning the CPU at 100% while waiting.
Upgrade all to use the latest RMR, version 4.0.5.
Tweak the example xapps to emit their names in log messages.
Improve documentation especially the package overview shown at PyPI.
Issue-ID: RIC-354
Signed-off-by: Lott, Christopher (cl778h) <cl778h@att.com>
Change-Id: I08692e6ef60d199cb0b92c1c99740ae808b8885c
diff --git a/docs/developer-guide.rst b/docs/developer-guide.rst
index 85a3cfd..06f01b7 100644
--- a/docs/developer-guide.rst
+++ b/docs/developer-guide.rst
@@ -4,34 +4,56 @@
Developer Guide
===============
-.. contents::
- :depth: 3
- :local:
+Tech Stack
+----------
+
+The framework requires Python version 3.7 or later, and depends on
+these packages provided by the O-RAN-SC project and third parties:
+
+* msgpack
+* mdclogpy
+* ricsdl
+
Version bumping the framework
-----------------------------
This project follows semver. When changes are made, the versions are in:
-1) ``docs/release-notes.rst``
-
-2) ``setup.py``
+#. ``docs/release-notes.rst``
+#. ``setup.py``
Version bumping RMR
-------------------
-These items in this repo must be kept in sync:
-* Dockerfile-Unit-Test
-* examples/Dockerfile-Ping
-* examples/Dockerfile-Pong
-* ``rmr-version.yaml`` controls what rmr gets installed for unit testing in Jenkins
+These items in this repo must be kept in sync with the RMR version:
+
+#. Dockerfile-Unit-Test
+#. examples/Dockerfile-Ping
+#. examples/Dockerfile-Pong
+#. ``rmr-version.yaml`` controls what version of RMR is installed for
+ unit testing in Jenkins CI
Unit Testing
------------
-You can run the unit tests in Docker to avoid installing RMR locally:
+Running the unit tests requires the python packages ``tox`` and ``pytest``.
+
+The RMR library is also required during unit tests. If running directly from tox
+(outside a Docker container), install RMR according to its instructions.
+
+Upon completion, view the test coverage like this:
::
- docker build -f Dockerfile-Unit-Test .
+ tox
+ open htmlcov/index.html
+
+Alternatively, if you cannot install RMR locally, you can run the unit
+tests in Docker. This is somewhat less nice because you don't get the
+pretty HTML report on coverage.
+
+::
+
+ docker build --no-cache -f Dockerfile-Unit-Test .
diff --git a/docs/installation-guide.rst b/docs/installation-guide.rst
index 0785c40..088490f 100755
--- a/docs/installation-guide.rst
+++ b/docs/installation-guide.rst
@@ -6,12 +6,8 @@
Installation Guide
==================
-.. contents::
- :depth: 3
- :local:
-
-The `ricxappframe` is available in `PyPi <https://pypi.org/project/ricxappframe>`_ .
-Use pip to install the version you want.
+The `ricxappframe` is available in `PyPI <https://pypi.org/project/ricxappframe>`_ .
+Use pip to install the version required.
Installing the ricxappframe package does NOT install the required RMR system library,
a shared object written in C and available for most Linux systems.
diff --git a/docs/overview.rst b/docs/overview.rst
index ffac38f..d087334 100644
--- a/docs/overview.rst
+++ b/docs/overview.rst
@@ -5,56 +5,105 @@
Framework Overview
==================
-This library is a framework for writing Xapps in python.
-There may or may not be many Xapps written in python; however rmr, sdl, and logging libraries all exist for python, and this framework brings them together.
+This package is a framework for writing Xapps in python. The framework
+reduces the amount of code required in an Xapp by providing common
+features needed by all Python-based Xapps including communication with
+the RIC message router (RMR) and the Shared Data Layer (SDL).
-There are (at the time of writing) two "kinds" of Xapps one can instantiate with this framework that model "push" (RMR Xapps) and "pull" (General Xapps), as described below.
+The framework was designed to suport many types of Xapps, including
+applications that are purely reactive to RMR messages, and
+applications that initiate actions according to other criteria.
-RMR Xapps
----------
-This class of Xapps are purely reactive to rmr; data is always "pushed" to it via rmr.
-That is, every time the Xapp receives an rmr message, they do something, then wait for the next message to arrive, end never need to execute functionality at another time (if they do, use the next class).
-This is represented by a series of callbacks that get registered to receive rmr message types.
-Every time an rmr message arrives, the user callback for that message type is invoked, or if the user has not registered a callback for that type, their default callback (mandatory) is invoked.
-An analogy of this is AWS Lambda: "execute this code every time an event comes in" (the code to execute can depend on the type of event).
+Reactive Xapps
+--------------
+
+A reactive Xapp acts on messages that are delivered (pushed) via RMR.
+The Xapp only takes action upon receipt of an RMR message. The Xapp
+never takes action at another time.
+
+This type of application is constructed by creating callback functions
+and registering them with the framework by message type. When an RMR
+message arrives, the appropriate callback is invoked. An Xapp may
+define and register a separate callback for each expected message
+type. Every Xapp must define a default callback function, which is
+invoked when a message arrives for which no type-specific callback was
+registered. An analogy of this is AWS Lambda: "execute this code
+every time an event comes in" (the code to execute can depend on the
+type of event).
General Xapps
-------------
-In this class of Xapp the user simply provides a function that gets invoked, and typically that function has a `while (something)` in it.
-If the function returns, the Xapp will stop.
-In this type of Xapp, the Xapp must "pull" it's own data, typically from SDL, rmr (ie query another component for data), or other sources.
-The framework is "lighter" in this case then the former; it sets up an SDL connection, an rmr thread, and then calls the client provided function.
-This is to be used for Xapps that are not purely event driven.
-RMR Threading in the framework
-------------------------------
-NOTE: this is an implementation detail!
-We expose this for transparency but most users will not have to worry about this.
+A general Xapp acts according to its own criteria, which may include
+receipt of RMR messages.
-In both types of Xapp, the framework launches a seperate thread whose only job is to read from rmr and deposit all messages (and their summaries) into a thread safe queue.
-When the client Xapp reads using the framework (this read is done by the framework itself in the RMR Xapp, but by the client in a general Xapp), the read is done from the queue.
-The framework is implemented this way so that a long running client function (e.g., consume) cannot block rmr reads.
-This is important because rmr is *not* a persistent message bus, if any rmr client does not read "fast enough", messages can be lost.
-So in this framework the client code is not in the same thread as the rmr reads, so that long running client code can never lead to lost messages.
+This type of application is constructed by creating a function that
+gets invoked by the framework. Typically that function contains a
+`while (something)` event loop. If the function returns, the Xapp
+stops. In this type of Xapp, the Xapp must fetch its own data, either
+from RMR, SDL or other source. The framework does less work for a
+general application compared to a reactive application. The framework
+sets up an RMR thread and an SDL connection, then invokes the
+client-provided function.
-In the case of RMR Xapps, there are currently 3 potential threads; the thread that reads from rmr directly, and the user can optionally have the rmr queue read run in a thread, returning execution back to the user thread.
-The default is only two threads however, where `.run` does not return back execution and the user code is "finished" at that point.
+Threading in the Framework
+--------------------------
+
+RMR interactions are processed in a thread started by the framework.
+This implementation detail is documented here for transparency, but
+most users will not have to worry about this.
+
+In both types of Xapp, the framework launches a separate thread whose
+only job is to read from RMR and deposit all messages (and their
+summaries) into a thread-safe queue. When the client Xapp reads from
+RMR using the framework (this read is done by the framework itself in
+the RMR Xapp, but by the client in a general Xapp), the read is done
+from the framework-managed queue. The framework is implemented this
+way so that a long-running client function (e.g., consume) will not
+block RMR reads. This is important because RMR is *not* a persistent
+message bus, if an RMR client does not read fast enough, messages can
+be lost. So in this framework the client code is not in the same
+thread as the RMR reads, to ensure that long-running client code will
+not cause message loss.
+
+In the case of RMR Xapps, there are currently 3 potential threads; the
+thread that reads from RMR directly, and the user can optionally have
+the RMR queue read run in a thread, returning execution back to the
+user thread. The default is only two threads however, where `.run`
+does not return back execution and the user code is finished at that
+point.
Healthchecks
------------
-RMRXapps come with a default rmr healthcheck probe handler.
-When the RMRXapp is sent an rmr healthcheck, it will check to see if the rmr thread is healthy (well it can't even reply if it's not!), and that the SDL connection is healthy.
-The Xapp responds accordingly.
-The user can override this default handler by registering a new callback to the appropriate message type.
-General Xapps must handle healthchecks when they read their rmr mailbox, since there is no notion of handlers.
+The framework provides a default RMR healthcheck probe handler for
+reactive Xapps. When an RMR healthcheck message arrives, this handler
+checks that the RMR thread is healthy (of course the Xapp cannot even
+reply if the thread is not healthy!), and that the SDL connection is
+healthy. The handler responds accordingly via RMA. The Xapp can
+override this probe handler by registering a new callback for the
+appropriate message type.
-There is no http service (Currently) in the framework therefore there are no http healthchecks.
+The framework provides no healthcheck handler for general Xapps. Those
+applications must handle healthcheck probe messages appropriately when
+they read their RMR mailboxes.
+
+There is no http service in the framework, so there is no support for
+HTTP-based healthcheck probes, such as what a deployment manager like
+Kubernetes may use.
Examples
--------
-There are two examples in the `examples` directory; `ping` which is a general Xapp, and `pong` which is an RMR Xapp.
-Ping sends a message, pong receives the message and use rts to reply.
-Ping then reads it's own mailbox and demonstrates other functionality.
-The highlight to note is that `pong` is purely reactive, it only does anything when a message is received.
-Ping uses a general that also happens to read it's rmr mailbox inside.
+
+Two sample Xapps using this framework are provided in the `examples`
+directory of the git repository. The first, `ping`, is a general Xapp
+that defines a main function that reads its RMR mailbox in addition to
+other work. The second, `pong`, is a reactive Xapp that only takes
+action when a message is received.
+
+To run a demonstration, build the Docker images for both examples
+using the supplied Dockerfiles. Then start the Pong container (the
+listener) followed by the Ping container (the sender). The Ping
+application sends a message, the pong application receives the message
+and use RMR's return-to-sender feature to reply. Ping then reads its
+own mailbox and demonstrates other functionality.
diff --git a/docs/release-notes.rst b/docs/release-notes.rst
index 8a5001f..74348c9 100644
--- a/docs/release-notes.rst
+++ b/docs/release-notes.rst
@@ -11,6 +11,12 @@
and this project adheres to `Semantic Versioning <http://semver.org/>`__.
+[1.1.1] - 2020-05-07
+--------------------
+* Use timeout on queue get method to avoid 100% CPU usage (`RIC-354 <https://jira.o-ran-sc.org/browse/RIC-354>`_)
+* Upgrade to RMR version 4.0.5
+
+
[1.1.0] - 2020-05-06
--------------------
* Use RMR timeout on receive to avoid 100% CPU usage (`RIC-354 <https://jira.o-ran-sc.org/browse/RIC-354>`_)