ModernBill Operation

The Concepts

Actions

Basically, actions are high-level request handlers, whether the request is initiated from a web browser, the command line, or an action API hit. Browsing the admin interface, running events from cron, and pushing products to a slave ModernBill are actions.

Commands
Data Manipulation

Commands which merely wrap around database access.

Process
Procedures

Commands which manipulate data in a complicated way, triggered by user input.

Events

ModernBill's automation involves "events", which ultimately trigger MBAPI process commands which either do time-specific data processes, like generating invoices, or hit remote APIs.

Modules

Commands which provide common, system-local interfaces to remote interfaces.

To understand system portability problems, the techniques these concepts use to interact with the underlying system need to be known. The rest of this section will discuss these interactions.

Action Dispatching

Stateless

Most web platforms, including PHP, execute a program for each HTTP request. No program state is persisted between requests. This is called the "stateless" model. The benefit of stateless programming is that the resources required scale lineally with the amount of requests. It is easy to scale by "throwing more hardware at the problem". The drawback is that all session-oriented objects need to be reconstructed for each request, so the higher the session overhead, the more latency occurs, no matter how many resources you have available because the latency is limited to the speed of whichever resource is being used.

Stateful

ModernBill has a very high session overhead, so a common complaint is high latency. One way to deal with this session latency is to reduce how often sessions need to be initialized, changing the model from "stateless" to "stateful". In the stateful model, requests are separated from sessions so that session instances can be kept initialized to allow multiple requests to be handled with the same session instance. The session latency only occurs when the session is created, at login.

The stateful model changes the performance characteristics so that the number and size of concurrent sessions are a factor, so the more requests per session, the higher the session overhead, the more performance benefits, as long as there is enough system memory to deal with the lingering sessions. If there is a lot of time between requests, and a lot of lingering sessions, system memory can be exhausted, but lowering the session timeout alleviates that problem.

Execution Methods

ModernBill has several modes of operation:

Stateless
Implementation

This is the usual model where the session is reconstructed for each request.

State

All state, per request, is reinitialized at the beginning and destroyed at the end.

Requirements

Requires nothing special.

Semi-Stateful
Implementation

ModernBill has experimental support for caching large pre-initialized components of sessions in shared memory. Since locales are often shared by sessions, and since the locale information is such a large component of sessions, it makes sense to cache the initialized locale objects. Nearly half of the session overhead is removed when this is done.

State

Most state, per request, is reinitialized at the beginning and destroyed at the end, but some is cached in system memory in its initialized state and is copied back into each request process as needed.

Requirements

Requires the sysvshm and sysvsem PHP extensions; only available on Unix systems.

Stateful
Implementation

ModernBill has highly experimental support for a stateful execution model. Currently, it is implemented by spawning a daemon session server on login.

State

All state, per session, subject to a timeout, is reinitialized at the beginning and destroyed at the end. Each request process merely serializes the request and response between the session server. Instead of copying part of the session, the request and response are copied.

Requirements

Requires the posix and pcntl PHP extensions, and a PHP SAPI that supports fork(2) and setsid(2), like cgi; only available on Unix systems.

Files of Interest

/lib-action/baseaction.php.php
Provides the dispatchAction() function.
/lib-tk/include/io/ipc.php
Provides an object-oriented interface to the System-V Inter-Process Communication functions provided by the sysvsem, sysvshm, and sysvmsg PHP extensions; used by the semi-stateful method.
/lib-tk/include/sessionServer/sessionServer.php
Provides functions for initializing and communicating with session servers.
/app-*/path.php
Bootstraps the action system for an MBAPI application. Provides the app-specific callbacks for serializing the request and response between session servers.
/lib-tk/daemon.php
Provides the daemonize() function used to spawn session servers.

Automation Dispatching

The way ModernBill executes background processes is dependent upon the PHP SAPI which dispatches the automation process. Ideally, ModernBill's background processes need to be able to run unfettered. Many processes are unable to recover from being killed while processing. For example, between the time when a remote API call is requested and when it returns. If ModernBill is subject to being killed mid-process by a web server script timeout, problems will likely occur over time.

At the back-end, all automation is performed by the ProcessSystemQueue MBAPI command. At the front-end, virtually all automation is initiated by the same internal action in ModernBill called RunEvents. The only exception is when an event is "Debug Run", in which case the internal action RunDebugEvent is called. RunDebugEvent is always called from a web server request, and just runs ProcessSystemQueue within that same request's execution environment. However, RunEvents recursively spawns execution environments as needed until all events are run.

Execution Methods

RunEvents can spawn an execution environment in three different ways, and can be dispatched in two different ways:

Ways RunEvents can be dispatched
  1. By selecting "Run Events" manually from within the admin interface.
  2. By the /app-modernbill-admin/sbin/runevents.php command-line script.
Ways RunEvents can spawn execution environments
  1. By using fsockopen() or cURL to do an HTTP request to RunEvents which handles a batch of events. When a batch of events is finished, it will recursively hit itself until all events are run. This is a hack, and is the most unreliable method. This method can be used both ways RunEvents can be dispatched.
  2. By using shell_exec() to execute RunEvents which handles all events remaining to be run. This method can be used only when RunEvents is dispatched from the command-line. This method is very reliable.
  3. By using fork(2) and setsid(2) to spawn a daemon process which handles all events remaining to be run. This method can be used both ways RunEvents can be dispatched, but depends on obscure features of PHP which are rarely available, and only works when the web server handles PHP using the CGI PHP SAPI. This method is very reliable, and is the only reliable method that works in both dispatch methods.

Files of Interest

/app-modernbill-admin/sbin/runevents.php
Bootstraps the process of creating a session for the Cron User admin and dispatching the RunEvents action, for running events on cron.
/app-modernbill-admin/sbin/runevents.sh
A helper wrapper for runevents.php to help with debugging.
/app-modernbill-admin/include/lib-action/events/RunEvents.php
The RunEvents action. This contains the logic for running a batch of events.
/app-modernbill-admin/include/lib-action/events/RunDebugEvent.php
The RunDebugEvent action.
/lib-tk/persist.php
Determines which spawning method is used by RunEvents.
/lib-tk/daemon.php
Provides the daemon spawning method.
/lib-modernbill/include/lib-mbapi/ProcessSystemQueue.php
The back-end MBAPI command which runs events. This file is encoded.

API Dispatching

Please see the article on ModernBill's Networking Libraries.