<?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="services">
  <title>TorqueBox Services</title>

  <section id="what-are-services">
    <title>What Are Services?</title>

    <para>Services are persistent background Ruby daemons deployed and
    managed by TorqueBox. Common uses for services include connecting
    to a remote service (IRC bot, Twitter Streaming API client) or
    starting a server to listen for incoming connections. A service
    may be deployed as part of a web application or as its own
    application without any web component. Services have full access
    to the entire Ruby environment. This means that a service deployed
    as part of a web application can use the app's database models,
    for example.</para>
  </section>

  <section id="service-classes">
    <title>Service Classes</title>

    <para>Each service maps to exactly one Ruby class that should
    optionally implement <methodname>initialize(Hash)</methodname>,
    <methodname>start()</methodname> and
    <methodname>stop()</methodname> methods which should each return
    quickly. Typically the <methodname>start</methodname> method will
    spawn a new thread to start an event loop or other long-running
    task.</para>

    <para><example>
      <title>Service implementation
      (<filename>my_service.rb</filename>)</title>

      <para><programlisting>class MyService
  def initialize(opts={})
    @name = opts['name']
  end

  def start
    Thread.new { run }
  end

  def stop
    @done = true
  end

  def run
    until @done
      puts "Hello #{@name}"
      sleep(1)
    end
  end
end</programlisting>This example service prints a message every second
until stopped.
      </para>
    </example></para>

    <para>
      The service's <methodname>start</methodname> method will be
      invoked when the service is deployed, and
      <methodname>stop</methodname> will be invoked automatically when
      the service is undeployed. Thus a convenient hook is provided
      for cleanly shutting down any threads or other resources used by
      the service.
    </para>

  </section>

  <section id="deploying-services">
    <title>Deploying Services</title>

    <para>Services are deployed by creating a <code>services</code>
    section inside your application's <link
    linkend="deployment-descriptors">deployment
    descriptor</link>.</para>

    <section id="services-format">
      <title>Configuration Format</title>

      <para>Within the internal <filename>torquebox.yml</filename> descriptor 
      (or through an external <filename><replaceable>*</replaceable>-knob.yml</filename> 
      descriptor), services reside under a <code>services</code> key of
      <filename>torquebox.yml</filename>. Each key underneath
      <code>services</code> is either a unique name for the service or
      the name of the Ruby class implementing the service. Providing a
      unique name allows the reuse of the same Ruby class to provide
      multiple services. If the Ruby class name is not used as the key, 
      it must be provided using the <code>service</code> key in the 
      key/value pairs nested underneath the service entry as 
      options for the service. Any value assigned to the <code>config</code>
      key underneath the service entry will be passed in as
      the parameter to the service's <methodname>initialize</methodname>
      method.</para>

      <para>If you are using the DSL (via <filename>torquebox.rb</filename>) in
      your internal descriptor, each service is defined using the 
      <methodname>service</methodname> directive, with very similar options to 
      the YAML syntax described above. The DSL does not require a name for 
      each job, unless you intend to share a job class across multiple jobs.</para>

      <para><example>
        <title>Example deployment descriptor</title>

        <para>Using the YAML syntax:<programlisting>services:
  MyService:
    config:
      name: TorqueBox User

  AnotherService:

  ham-machine:
    service: FoodMachine
    config: 
      food: ham
  
  biscuit-machine:
    service: FoodMachine
    config:
      food: biscuit</programlisting>This deploys four services;
        the first two using the class name as the key:
        <classname>MyService</classname> which corresponds to the
        example above and <classname>AnotherService</classname>
        which doesn't take any initialization parameters. The
        latter two services reuse the same class, and use a
        unique name as the key.</para>
        
       <para>And using the DSL:<programlisting>TorqueBox.configure do 
  ...
  service MyService do 
    config do
      name 'TorqueBox User'
    end
  end

  service AnotherService

  service FoodMachine do
    name 'ham-machine'
    config do
      food 'ham'
    end
  end

  service FoodMachine do
    name 'biscuit-machine'
    config do
      food 'biscuit'
    end
  end</programlisting></para>
      </example></para>

      <para>Service classes should be placed in a directory that is on the application's 
      load path. For Rails applications, the convention is to put your service
      classes in <filename>$RAILS_ROOT/app/services/</filename>. For non-Rails applications,
      the convention is to use <filename>$RAILS_ROOT/services/</filename>. No matter what
      type of application you have, both directories will automatically be added to the 
      load path.</para>

    </section>
  </section>

  <section id="clustered-services">
    <title>Clustered Services</title>

    <section id="ha-singleton-services">
      <title>High Availability Singleton Services</title>

      <para>TorqueBox supports highly-available singleton services. By
      default, a service only runs on one node in a cluster and if
      that node fails or the service is interrupted for any reason, it
      automatically starts on another node.</para>

      <para>To use highly-available singleton services, you must start
      TorqueBox with a clustered configuration. For example:</para>

      <para><screen> <prompt>$</prompt> <command>$JBOSS_HOME/bin/standalone.sh --server-config=standalone-ha.xml</command></screen></para>

      <para>
        Alternatively, use the <command>torquebox</command> command:
        <screen> <prompt>$</prompt> <command>torquebox run --clustered</command></screen>
      </para>

      <para>HA services are configured using the
      <code>singleton</code> key in the services section of
      <filename>torquebox.yml</filename>. Its default value is
      <code>true</code> so you must manually configure it with a value
      of <code>false</code> for the service to run on every node in
      the cluster.</para>

      <para><example>
        <title>Example deployment descriptor</title>

        <para>Using the YAML syntax:<programlisting>services:
  MyService:
    config:
      name: TorqueBox User

  AnotherService:

  ham-machine:
    singleton: false
    service: FoodMachine
    config: 
      food: ham
  
  biscuit-machine:
    singleton: false
    service: FoodMachine
    config:
      food: biscuit</programlisting></para>
        
       <para>And using the DSL:<programlisting>TorqueBox.configure do 
  ...
  service MyService do 
    config do
      name 'TorqueBox User'
    end
  end

  service AnotherService

  service FoodMachine do
    name 'ham-machine'
    singleton false
    config do
      food 'ham'
    end
  end

  service FoodMachine do
    name 'biscuit-machine'
    singleton false
    config do
      food 'biscuit'
    end
  end</programlisting>This is the same
        deployment descriptor from the example above but
        this time <classname>FoodMachine</classname> services are
        configured to run on all nodes in the cluster. The
        <classname>MyService</classname> and
        <classname>AnotherService</classname> services are
        singletons and will only run on one node in the cluster.
       </para>
      </example></para>
    </section>

    <section id="services-running-on-every-node">
      <title>Services Running on Every Node</title>

      <para>
        To configure your services to run on all nodes in a cluster,
        set <code>singleton</code> to <code>false</code> in the
        deployment descriptor.
      </para>
    </section>

  </section>

  <section id="resouce-injection-with-services">
    <title>Resource Injection with Services</title>

    <para>If a service requires access to other resources, such as messaging
    topics and queues, or Java CDI components these should be injected using
    the resource injection facilities provided by TorqueBox (see <xref
    linkend="resource-injection" />).</para>

    <para>In order for resource injection to function with services,
    they must reside either at the root of your application directory (typical
    for simple Rack applications), or underneath an
    <filename>app/services/</filename> directory. If you place the service anywhere
    else, it may still function, but resources injection will not be
    available.</para>
  </section>
</chapter>
