JBoss.orgCommunity Documentation

Chapter 16. TorqueBox Runtime Pooling

16.1. Types of Runtime Pools
16.2. Subsystem Pools
16.3. Configuration
16.3.1. Syntax
16.3.2. Examples
16.4. Runtime Initialization

To run Ruby code inside a Java application server, the TorqueBox platform requires a Ruby interpreter, provided by JRuby. TorqueBox provides a simple but flexible means of mapping the app server's threads of execution to one or more Ruby interpreters, giving you complete concurrency control, but the defaults should be reasonable.

TorqueBox defines two types of pools from which a Ruby interpreter may be obtained:

Bounded pools

A bounded pool is a typical resource pool with minimum and maximum capacity. Each interpreter managed by the pool is given out to a single client at a time. It is unavailable for any other client until the current owner returns it to the pool. The pool will ensure that a minimum number of interpreters are kept in the pool at all times. Additionally, a maximum capacity is specified to ensure that the pool does not grow unbounded. Clients requesting an interpreter from a pool with no available interpreters will block until an interpreter becomes available. Interpreters may become available through other clients returning an existing interpreter, or by the pool spinning up additional interpreters, if it has not reached its maximum capacity.

Shared pools

A shared pool is a false pool. A shared pool contains one Ruby interpreter that is allowed to be shared, concurrently, with an unbounded number of clients. A shared pool may only be used in cases where the application is considered threadsafe. An application's threadsafety may be affected by both framework code and deployment factors. These issues are discussed below.

As noted above, an advanced application may use the functionality of multiple subsystems. Each subsystem is configured to use a distinct pool in order to provide a modicum of isolation and prevent wayward interaction. The configuration of various subsystem pools are affected by how the application is deployed. Each subsystem is automatically configured using reasonable defaults, but may be completely configured manually through a deployment descriptor (see Chapter 5, TorqueBox Deployment Descriptors).

Web (Rack)

The web subsystem, powering Rack applications, defaults to deploying a shared pool. Modern frameworks have mostly moved away from their assumption of single-threaded applications. By using a shared pool, resources are conserved, and a single Ruby interpreter may handle all requests from web clients.

Scheduled Jobs

The pool deployed for the scheduled jobs subsystem varies based on the deployment mode of the application. In development mode, automatic code-reloading is desirable, but multiple jobs executing and/or resetting the application within a single interpreter causes race conditions and poor interactions. For this reason, a non-shared bounded pool is configured when the application is deployed in development mode. In non-development deployments, reloading is disabled, and the race conditions do not exist. In the non-development cases, a more efficient shared pool is configured for the application.

Message Processors

As with the jobs subsystem, asynchronous message processing introduces race conditions between processors executing and processors attempted to reset the application. Likewise, the pool for the message processor subsystem uses a bounded pool when the application is deployed in development mode, otherwise it uses the more efficient shared pool strategy.

If your application is not designed to be thread-safe, you can instead pool the interpreters resulting in a single-threaded model. You can do this for jobs, messaging, and/or web requests. Typically, if your application creates and uses global variables to manage state for a single web request, you may have problems with the default multi-threaded behavior.

To modify the default interpreter pool configuration, you can add pooling: section to either your application's internal deployment descriptor, or through an external *-knob.yml descriptor. This section is always optional, and only required if you wish to modify the defaults.

Within a deployment descriptor, a block may be added for each susbsystem you desire to explicitly configure. Any subsystem not mentioned will be configured with its defaults. Configuration of each type of pool is slightly different.

Scheduled jobsjobs
Message Processorsmessaging
Bounded pools

A bounded pool has a type parameter of 'bounded' and requires two additional parameters: min and max. The min parameter specifies the minimum number of managed interpreters that pool should initialize itself with. The max parameter specifies the largest capacity the pool should ever grow to in order to satisfy client requests.

Shared pools

A shared pool requires no configuration other than indicating a subsystem should use a shared pool.

Lazy pools

A lazy pool is a bounded or shared pool that does not start until it is needed. So, a lazy messaging pool would not start until the first message was received. A lazy web pool would not start until the first web request cames in. An eager pool (opposite of lazy), on the other hand, starts when the application is deployed even if it isn't needed yet.

Ruby runtimes are initialized with standard load paths, such as ./lib enabled. Rails applications benefit from the load path magic that Rails performs automatically. For non-rails applications, TorqueBox initializes Ruby runtimes with ./lib and ./config added to the load path. Additionally, for custom runtime initialization, you may place a torquebox_init.rb in ./config or the root directory of your application. This file will be evaluated for all runtimes as they are initialized.