<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd">
<chapter id="pooling">
  <title>TorqueBox Runtime Pooling</title>

  <para>To run Ruby code inside a Java application server, the TorqueBox
  platform requires a Ruby interpreter, provided by <ulink
  url="http://www.jruby.org">JRuby</ulink>. 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.</para>

  <section id="types-of-pools">
    <title>Types of Runtime Pools</title>

    <para>TorqueBox defines two types of pools from which a Ruby interpreter
    may be obtained:</para>

    <itemizedlist spacing="compact">
      <listitem>
        <para>Bounded</para>
      </listitem>

      <listitem>
        <para>Shared</para>
      </listitem>
    </itemizedlist>

    <formalpara>
      <title>Bounded pools</title>

      <para>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.</para>
    </formalpara>

    <formalpara>
      <title>Shared pools</title>

      <para>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.</para>
    </formalpara>
  </section>

  <section id="subsystem-pools">
    <title>Subsystem Pools</title>

    <para>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 
    <xref linkend="deployment-descriptors">deployment descriptor</xref>).</para>

    <formalpara>
      <title>Web (Rack)</title>

      <para>The web subsystem, powering Rack applications, defaults to
      deploying a <emphasis>shared</emphasis> 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.</para>
    </formalpara>

    <formalpara>
      <title>Scheduled Jobs</title>

      <para>The pool deployed for the scheduled jobs subsystem varies based on
      the deployment mode of the application. In <code>development</code>
      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
      <emphasis>bounded pool</emphasis> is configured when the application is
      deployed in <code>development</code> mode. In
      non-<code>development</code> deployments, reloading is disabled, and the
      race conditions do not exist. In the non-development cases, a more
      efficient <emphasis>shared pool</emphasis> is configured for the
      application.</para>
    </formalpara>

    <formalpara>
      <title>Message Processors</title>

      <para>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 <emphasis>bounded pool</emphasis> when the
      application is deployed in development mode, otherwise it uses the more
      efficient <emphasis>shared pool</emphasis> strategy.</para>
    </formalpara>
  </section>

  <section id="pooling-configuration">
    <title>Configuration</title>

    <para>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.</para>

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

    <section id="pooling-configuration-syntax">
      <title>Syntax</title>

      <para>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.</para>

      <informaltable>
        <tgroup cols="2">
          <colspec align="left" />

          <thead>
            <row>
              <entry>Subsystem</entry>

              <entry>Key</entry>
            </row>
          </thead>

          <tbody>
            <row>
              <entry>Web/Rack</entry>

              <entry><code>web</code></entry>
            </row>

            <row>
              <entry>Scheduled jobs</entry>

              <entry><code>jobs</code></entry>
            </row>

            <row>
              <entry>Message Processors</entry>

              <entry><code>messaging</code></entry>
            </row>

            <row>
              <entry>Services</entry>

              <entry><code>services</code></entry>
            </row>

            <row>
              <entry>Stomplets</entry>

              <entry><code>stomplets</code></entry>
            </row>
          </tbody>
        </tgroup>
      </informaltable>

      <formalpara>
        <title>Bounded pools</title>

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

      <example>
        <title>Configuring a bounded pool</title>

        <para>Using the YAML syntax:<programlisting>pooling:
  web:
    type: bounded
    min: 3
    max: 10</programlisting></para>
      
       <para>And via the DSL:<programlisting>TorqueBox.configure do
  ...
  pool :web do
    type :bounded
    min 3
    max 10
  end
end</programlisting></para>
      </example>

      <formalpara>
        <title>Shared pools</title>

        <para>A shared pool requires no configuration other than indicating a
        subsystem should use a shared pool.</para>
      </formalpara>

      <example>
        <title>Configuring a shared pool</title>

        <para>Using the YAML syntax:<programlisting>pooling:
  web:
    type: shared</programlisting></para>

        <para>And via the DSL:<programlisting>TorqueBox.configure do  
  ...
  pool :web do
    type :shared
  end
end</programlisting></para>
      </example>

      <formalpara>
        <title>Lazy pools</title>

        <para>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.</para>
      </formalpara>

      <example>
        <title>Configuring eager and lazy pools</title>

        <para>Using the YAML syntax:<programlisting>pooling:
  web:
    lazy: false
  jobs:
    lazy: true</programlisting></para>

        <para>And via the DSL:<programlisting>TorqueBox.configure do
  ...
  pool :web do
    lazy false
  end
  pool :jobs do
    lazy true
  end
end</programlisting></para>
      </example>
    </section>

    <section id="pooling-examples">
      <title>Examples</title>

      <example id="pooling-examples-default">
        <title>Default development-mode pooling</title>

        <para>Using the YAML syntax:<programlisting>application:
  <replaceable>...</replaceable>

pooling:
  jobs: 
    type: bounded
    min: 1
    max: 2
    lazy: true
  messaging:
    type: bounded
    min: 1
    max: 2
    lazy: true
  web:
    type: shared
    lazy: false</programlisting></para>

        <para>And via the DSL:<programlisting>TorqueBox.configure do
  ...
  pool :jobs do
    type :bounded
    min 1
    max 2
    lazy true
  end

  pool :messaging do
    type :bounded
    min 1
    max 2
    lazy true
  end

  pool :web, :type => :shared, :lazy => false
end</programlisting></para>
        <para>Above is the implicit default
        configuration for an application deployed in <code>development</code>
        mode.</para>
      </example>

      <example id="pooling-yaml-examples-non-devmode">
        <title>Default non-development-mode pooling</title>

        <para>Using the YAML syntax:<programlisting>application:
  ...

pooling:
  jobs:
    type: shared
    lazy: true
  messaging:
    type: shared
    lazy: true
  web:
    type: shared
    lazy: false</programlisting></para>

        <para>And via the DSL:<programlisting>TorqueBox.configure do
  ...
  pool :jobs, :type => :shared, :lazy => true
  pool :messaging, :type => :shared, :lazy => true
  pool :web, :type => :shared, :lazy => false
end</programlisting></para>
        <para>Above is the implicit default
        configuration for an application deployed in a mode other than
        <code>development</code>.</para>
      </example>
    </section>
  </section>

  <section id="runtime-initialization">
    <title>Runtime Initialization</title>

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


  </section>
</chapter>
