uclug torquebox - 03/08/2011
DESCRIPTION
TRANSCRIPT
UCLUGMarch 2011
Creative Commons BY-SA 3.0
Toby Crawley
Thursday, March 10, 2011
whoami
• C > Java > PHP > Java > Ruby > Java?
• emacs, though I’ve heard of vi
• Red Hat Senior Engineer
• proud member of
Thursday, March 10, 2011
Agenda• High-level structure and TorqueBox
setup
• Web, Messaging, Scheduling, Services, Clustering
Thursday, March 10, 2011
TorqueBoxthe power of JBoss with the expressiveness of Ruby
Thursday, March 10, 2011
TorqueBox: what?
• A “real” app server for Ruby
• Founded in 2008
• Bob McWhirter’s “labor of love”
• 100% open-source, LGPL license
• Reflects a strong commitment to Ruby from Red Hat
Thursday, March 10, 2011
TorqueBox: why?
• “Native” support for Rack apps
• Built-in background processing
• Built-in scheduling
• Built-in clustering
• Easily scalable
• Optionally enterprisey
Thursday, March 10, 2011
JRubya good idea done well
Thursday, March 10, 2011
JRuby: why?
• Very fast runtime
• Real threads
• Java libraries
• Java tools
• Healthy community
Thursday, March 10, 2011
JRuby: why not?
• Slower start up
• Native gems
• FFI
• C extension support
• Some Ruby libs not thread-safe
Thursday, March 10, 2011
JBoss ASthe enterprisey good parts
Thursday, March 10, 2011
I promise...
• No XML
• No Java *
• No war files *
• Only Ruby and YAML
* Unless you really want to
Thursday, March 10, 2011
JBoss AS6
• Tomcat for web
• Infinispan for caching
• HornetQ for messaging
• Quartz for scheduling
• PicketBox for authentication
• mod_cluster for clustering
Thursday, March 10, 2011
AS = Application Server
• Not just “web server + interpreter”
• More like initd than httpd
• Can host multiple, disparate apps simultaneously
• Provides basic services to all the apps it hosts
Thursday, March 10, 2011
Hot Deployment
• anything added to deploy/ will get deployed
• anything removed from deploy/ will get undeployed
• anything updated in deploy/ will get redeployed
• TorqueBox deployers make JBoss grok YAML and ruby archives
$JBOSS_HOME/server/default/deploy/
Thursday, March 10, 2011
Hot Deployment
• anything added to deploy/ will get deployed
• anything removed from deploy/ will get undeployed
• anything updated in deploy/ will get redeployed
• TorqueBox deployers make JBoss grok YAML and ruby archives
$JBOSS_HOME/server/default/deploy/
deployment descriptors
Thursday, March 10, 2011
Hot Deployment
• anything added to deploy/ will get deployed
• anything removed from deploy/ will get undeployed
• anything updated in deploy/ will get redeployed
• TorqueBox deployers make JBoss grok YAML and ruby archives
$JBOSS_HOME/server/default/deploy/
deployment descriptors
Thursday, March 10, 2011
Hot Deployment
• anything added to deploy/ will get deployed
• anything removed from deploy/ will get undeployed
• anything updated in deploy/ will get redeployed
• TorqueBox deployers make JBoss grok YAML and ruby archives
$JBOSS_HOME/server/default/deploy/
zip files (archives)
Thursday, March 10, 2011
Hot Deployment
• anything added to deploy/ will get deployed
• anything removed from deploy/ will get undeployed
• anything updated in deploy/ will get redeployed
• TorqueBox deployers make JBoss grok YAML and ruby archives
$JBOSS_HOME/server/default/deploy/
zip files (archives)
Thursday, March 10, 2011
Setting Up TorqueBoxin 3 easy steps!
Thursday, March 10, 2011
easy install
$ wget http://torquebox.org/torquebox-dev.zip$ unzip torquebox-dev.zip
$ export TORQUEBOX_HOME=$PWD/torquebox-1*$ export JBOSS_HOME=$TORQUEBOX_HOME/jboss$ export JRUBY_HOME=$TORQUEBOX_HOME/jruby
$ export PATH=$JRUBY_HOME/bin:$PATH
Thursday, March 10, 2011
easy install
$ wget http://torquebox.org/torquebox-dev.zip$ unzip torquebox-dev.zip
$ export TORQUEBOX_HOME=$PWD/torquebox-1*$ export JBOSS_HOME=$TORQUEBOX_HOME/jboss$ export JRUBY_HOME=$TORQUEBOX_HOME/jruby
$ export PATH=$JRUBY_HOME/bin:$PATH
Thursday, March 10, 2011
easy install
$ wget http://torquebox.org/torquebox-dev.zip$ unzip torquebox-dev.zip
$ export TORQUEBOX_HOME=$PWD/torquebox-1*$ export JBOSS_HOME=$TORQUEBOX_HOME/jboss$ export JRUBY_HOME=$TORQUEBOX_HOME/jruby
$ export PATH=$JRUBY_HOME/bin:$PATH
Thursday, March 10, 2011
easy install
$ wget http://torquebox.org/torquebox-dev.zip$ unzip torquebox-dev.zip
$ export TORQUEBOX_HOME=$PWD/torquebox-1*$ export JBOSS_HOME=$TORQUEBOX_HOME/jboss$ export JRUBY_HOME=$TORQUEBOX_HOME/jruby
$ export PATH=$JRUBY_HOME/bin:$PATH
Make sure the jruby found in your path is in $JRUBY_HOME/bin.
Thursday, March 10, 2011
easy install
$ wget http://torquebox.org/torquebox-dev.zip$ unzip torquebox-dev.zip
$ export TORQUEBOX_HOME=$PWD/torquebox-1*$ export JBOSS_HOME=$TORQUEBOX_HOME/jboss$ export JRUBY_HOME=$TORQUEBOX_HOME/jruby
$ export PATH=$JRUBY_HOME/bin:$PATH
Make sure the jruby found in your path is in $JRUBY_HOME/bin.
Thursday, March 10, 2011
easy install
$ jruby -S gem install bundler$ jruby -S gem install rails$ jruby -S gem install sinatra
Thursday, March 10, 2011
Rakefile
rake tasks
require "torquebox-rake-support"
Thursday, March 10, 2011
rake tasks
rake torquebox:run Run TorqueBox server
rake torquebox:deploy[context_path] Deploy the app in the current directory
rake torquebox:undeploy Undeploy the app in the current directory
Thursday, March 10, 2011
rake tasks
Start torquebox:run in its own shell and leave it running. Instead of script/server or shotgun or thin or whatever else, use torquebox:deploy.
Thursday, March 10, 2011
deployment descriptors
torquebox:deploy creates a deployment descriptor in the JBoss deploy/ directory
Thursday, March 10, 2011
deploy/myapp-knob.yml
deployment descriptors
application: root: /path/to/myapp env: developmentweb: context: myapp host: www.yourhost.com static: public rackup: config.ruenvironment: MAIL_HOST: mail.yourhost.com REPLY_TO: [email protected]
Thursday, March 10, 2011
deploy/myapp-knob.yml
deployment descriptors
application: root: /path/to/myapp env: developmentweb: context: myapp host: www.yourhost.com static: publicenvironment: MAIL_HOST: mail.yourhost.com REPLY_TO: [email protected]
The fully-qualified path to the app.
This will be the value of either
RAILS_ROOT or RACK_ROOT
Thursday, March 10, 2011
deploy/myapp-knob.yml
deployment descriptors
application: root: /path/to/myapp env: developmentweb: context: myapp host: www.yourhost.com static: publicenvironment: MAIL_HOST: mail.yourhost.com REPLY_TO: [email protected]
The fully-qualified path to the app.
This will be the value of either
RAILS_ROOT or RACK_ROOT
Thursday, March 10, 2011
deploy/myapp-knob.yml
deployment descriptors
application: root: /path/to/myapp env: developmentweb: context: myapp host: www.yourhost.com static: publicenvironment: MAIL_HOST: mail.yourhost.com REPLY_TO: [email protected]
The runtime mode of the app. This will be either RAILS_ENV
or RACK_ENV
Thursday, March 10, 2011
deploy/myapp-knob.yml
deployment descriptors
application: root: /path/to/myapp env: developmentweb: context: myapp host: www.yourhost.com static: publicenvironment: MAIL_HOST: mail.yourhost.com REPLY_TO: [email protected]
The runtime mode of the app. This will be either RAILS_ENV
or RACK_ENV
Thursday, March 10, 2011
deploy/myapp-knob.yml
deployment descriptors
application: root: /path/to/myapp env: developmentweb: context: myapp host: www.yourhost.com static: publicenvironment: MAIL_HOST: mail.yourhost.com REPLY_TO: [email protected]
The app’s context path (or “sub URI”):
http://localhost:8080/myappCan be set via rake:
rake torquebox:deploy[myapp]The default is root:
http://localhost:8080/
Thursday, March 10, 2011
deploy/myapp-knob.yml
deployment descriptors
application: root: /path/to/myapp env: developmentweb: context: myapp host: www.yourhost.com static: publicenvironment: MAIL_HOST: mail.yourhost.com REPLY_TO: [email protected]
The app’s context path (or “sub URI”):
http://localhost:8080/myappCan be set via rake:
rake torquebox:deploy[myapp]The default is root:
http://localhost:8080/
Thursday, March 10, 2011
deploy/myapp-knob.yml
deployment descriptors
application: root: /path/to/myapp env: developmentweb: context: myapp host: www.yourhost.com static: publicenvironment: MAIL_HOST: mail.yourhost.com REPLY_TO: [email protected]
A list of virtual hostnames to which
to bind the app.
Thursday, March 10, 2011
deploy/myapp-knob.yml
deployment descriptors
application: root: /path/to/myapp env: developmentweb: context: myapp host: www.yourhost.com static: publicenvironment: MAIL_HOST: mail.yourhost.com REPLY_TO: [email protected]
A list of virtual hostnames to which
to bind the app.
Thursday, March 10, 2011
deploy/myapp-knob.yml
deployment descriptors
application: root: /path/to/myapp env: developmentweb: context: myapp host: www.yourhost.com static: publicenvironment: MAIL_HOST: mail.yourhost.com REPLY_TO: [email protected]
The location of the app’s static
content, either absolute or relative to the app’s root.
Thursday, March 10, 2011
deploy/myapp-knob.yml
deployment descriptors
application: root: /path/to/myapp env: developmentweb: context: myapp host: www.yourhost.com static: publicenvironment: MAIL_HOST: mail.yourhost.com REPLY_TO: [email protected]
The location of the app’s static
content, either absolute or relative to the app’s root.
Thursday, March 10, 2011
deploy/myapp-knob.yml
deployment descriptors
application: root: /path/to/myapp env: developmentweb: context: myapp host: www.yourhost.com static: publicenvironment: MAIL_HOST: mail.yourhost.com REPLY_TO: [email protected]
Any environment variables required
by the app.
Thursday, March 10, 2011
deploy/myapp-knob.yml
deployment descriptors
application: root: /path/to/myapp env: developmentweb: context: myapp host: www.yourhost.com static: publicenvironment: MAIL_HOST: mail.yourhost.com REPLY_TO: [email protected]
Any environment variables required
by the app.
Thursday, March 10, 2011
deployment descriptors
• config/torquebox.yml
• internal descriptors have the same structure as the external ones in deploy/
•may be used to provide your own reasonable defaults
Thursday, March 10, 2011
Webmake rack, not war
Thursday, March 10, 2011
jruby-rack
• All rack-based frameworks supported: rails, sinatra, etc
• No packaging required: apps deploy from where they sit on disk
• No redeploy necessary to see changes when using rack reloading or rails development mode
Thursday, March 10, 2011
Gemfile
database connectivity
gem "activerecord-jdbc-adapter"
gem "jdbc-postgres"# gem "jdbc-sqlite3"# gem "jdbc-mysql"
Thursday, March 10, 2011
rails template
• Adds TorqueBox rake tasks
• Adds the JDBC sqlite3 gems
• Adds TorqueBox session_store
• Adds Backgroundable module
Thursday, March 10, 2011
my first rails app
$ jruby -S gem install bundler rails
$ jruby -S rails new myapp -m \ $TORQUEBOX_HOME/share/rails/template.rb
$ cd myapp$ jruby -S bundle install
$ jruby -S rake torquebox:deploy
Thursday, March 10, 2011
Messagingasynchronicity
Thursday, March 10, 2011
lots of options
Thursday, March 10, 2011
Resque
ActiveMessaging
cron
Taskr
rufus-scheduler
ConveyorWorkerQueue
Ap4r
CronEdit
lots of options
RailsCronOpen4
Spawn
Sparrow
Kestral
RabbitMQ
ActiveMQ
Amazon SQS
beanstalkd
starling
workling
async_observer
daemons
BackgroundDRb
BackgroundJob
Background-Fu
JobFu
DelayedJob
rake
Thursday, March 10, 2011
TorqueBox::Messaging
• JMS (Java Message Service) is an API for messaging
•HornetQ is the JBoss JMS implementation
Thursday, March 10, 2011
TorqueBox::Messaging
• No extra tables in your database
• No external system to manage
• Little to no config required at all
• System gets redeployed w/app
• Efficient loading of rails environment
• Automatic load balancing and retries
• Works on Windows, if you care
Thursday, March 10, 2011
app/tasks/email_task.rb
Tasks
class EmailTask < TorqueBox::Messaging::Task def welcome(payload) person = Person.find_by_id(payload[:id]) if person # send the email person.welcomed = true person.save! end endend
Thursday, March 10, 2011
app/tasks/email_task.rb
Tasks
class EmailTask < TorqueBox::Messaging::Task def welcome(payload) person = Person.find_by_id(payload[:id]) if person # send the email person.welcomed = true person.save! end endend
Thursday, March 10, 2011
app/tasks/email_task.rb
Tasks
class EmailTask < TorqueBox::Messaging::Task def welcome(payload) person = Person.find_by_id(payload[:id]) if person # send the email person.welcomed = true person.save! end endend
Thursday, March 10, 2011
app/tasks/email_task.rb
Tasks
class EmailTask < TorqueBox::Messaging::Task def welcome(payload) person = Person.find_by_id(payload[:id]) if person # send the email person.welcomed = true person.save! end endend
Thursday, March 10, 2011
app/controllers/people_controller.rb
Tasks
class PeopleController < ApplicationController def create @person = Person.new(params[:person]) respond_to do |format| if @person.save EmailTask.async(:welcome, :id => person.id) # respond appropriately end end endend
Thursday, March 10, 2011
app/controllers/people_controller.rb
Tasks
class PeopleController < ApplicationController def create @person = Person.new(params[:person]) respond_to do |format| if @person.save EmailTask.async(:welcome, :id => person.id) # respond appropriately end end endend
Thursday, March 10, 2011
Tasks
Call them from your controllers, models, and observers, or even other tasks. Even in non-Rails apps!
Thursday, March 10, 2011
Backgroundable
Inspired by DelayedJob’s handle_asynchronously, it’s trivial to create implicit background Tasks.
Thursday, March 10, 2011
lib/something.rb
Backgroundable
include TorqueBox::Messaging
class Something include Backgroundable always_background :foo def foo;; end def bar;; [email protected]@something.background.bar
Thursday, March 10, 2011
lib/something.rb
Backgroundable
include TorqueBox::Messaging
class Something include Backgroundable always_background :foo def foo;; end def bar;; [email protected]@something.background.bar
Thursday, March 10, 2011
lib/something.rb
Backgroundable
include TorqueBox::Messaging
class Something include Backgroundable always_background :foo def foo;; end def bar;; [email protected]@something.background.bar
Thursday, March 10, 2011
lib/something.rb
Backgroundable
include TorqueBox::Messaging
class Something include Backgroundable always_background :foo def foo;; end def bar;; [email protected]@something.background.bar
Thursday, March 10, 2011
app/models/slow_poke.rb
Backgroundable
class SlowPoke < ActiveRecord::Base always_background :takes_forever def takes_forever;; end def might_take_awhile;; endend
@[email protected]_take_awhile
Thursday, March 10, 2011
Queues
Tasks are built on top of Queues. Of course, you may build your own messaging based apps by defining your own Queues, Topics, and their message Processors yourself.
Thursday, March 10, 2011
config/torquebox.yml
Queues
queues: /queues/questions:
/queues/answers: durable: false
Thursday, March 10, 2011
Processors
You can create a processor class to receive messages from a Topic or Queue
Thursday, March 10, 2011
config/torquebox.yml
Processors
messaging: /topics/print: - PrintHandler - PopularHandler concurrency: 5 /queues/students: PrintHandler: config: color: true
Thursday, March 10, 2011
config/torquebox.yml
Processors
messaging: /topics/print: - PrintHandler - PopularHandler concurrency: 5 /queues/students: PrintHandler: config: color: true
Thursday, March 10, 2011
config/torquebox.yml
Processors
messaging: /topics/print: - PrintHandler - PopularHandler concurrency: 5 /queues/students: PrintHandler: config: color: true
Thursday, March 10, 2011
config/torquebox.yml
Processors
messaging: /topics/print: - PrintHandler - PopularHandler concurrency: 5 /queues/students: PrintHandler: config: color: true
Thursday, March 10, 2011
app/models/print_handler.rb
Processors
include TorqueBox::Messaging
class PrintHandler < MessageProcessor def on_message(body) puts "Processing #body of #message" end def configure(opts) @color = opts['color'] endend
Thursday, March 10, 2011
Queues (again)
But how do you send a message?
Thursday, March 10, 2011
example
Queues
include TorqueBox::Messagingquestions = Queue.new '/queues/questions'answers = Queue.new '/queues/answers' Thread.new do questions.publish "What time is it?" puts answers.receive( :timeout => 1000 )end puts questions.receiveanswers.publish Time.now
Thursday, March 10, 2011
example
Queues
include TorqueBox::Messagingquestions = Queue.new '/queues/questions'answers = Queue.new '/queues/answers' Thread.new do questions.publish "What time is it?" puts answers.receive( :timeout => 1000 )end puts questions.receiveanswers.publish Time.now
Thursday, March 10, 2011
example
Queues
include TorqueBox::Messagingquestions = Queue.new '/queues/questions'answers = Queue.new '/queues/answers' Thread.new do questions.publish "What time is it?" puts answers.receive( :timeout => 1000 )end puts questions.receiveanswers.publish Time.now
Thursday, March 10, 2011
example
Queues
include TorqueBox::Messagingquestions = Queue.new '/queues/questions'answers = Queue.new '/queues/answers' Thread.new do questions.publish "What time is it?" puts answers.receive( :timeout => 1000 )end puts questions.receiveanswers.publish Time.now
Thursday, March 10, 2011
Topics
• behavior is different, but interface is the same.
• all subscribers of a topic see each message, but only one subscriber will see any message from a queue
• use topics: section of torquebox.yml to define topics
• use TorqueBox::Messaging::Topic
Thursday, March 10, 2011
Schedulingget regular later
Thursday, March 10, 2011
app/jobs/newsletter_sender.rb
Jobs
class NewsletterSender def run() subscriptions = Subscription.find(:all) subscriptions.each do |e| send_newsletter( e ) end end end
Thursday, March 10, 2011
config/torquebox.yml
Jobs
jobs: monthly_newsletter: description: first of month job: NewsletterSender cron: ‘0 0 0 1 * ?’ process_tps_reports: job: TPSReportProcessor cron: ‘0 0 0 0 MON ?’
Thursday, March 10, 2011
Seconds Minutes Hours DOM Month DOW Year
0-59 0-59 0-23 1-31? L W
1-12JAN-DEC
1-7SUN-SAT? L #
1970-2099empty
0 */30 10-13 ? * FRI#3
“Fire every half hour from 10am until 1pm on the third Friday of each month”
Jobs
Thursday, March 10, 2011
Jobs
• More portable. What is the first day of the week on BSD again? What’s cron on Windows?
• Self contained within the app. No external systems to manage and keep in sync.
• Full rails environment loaded and available.
Thursday, March 10, 2011
Servicesrun along, lil’ daemon
Thursday, March 10, 2011
Services
Long-running, non-web “daemons” that share the runtime environment and deployment lifecycle of your app.
Thursday, March 10, 2011
Services• Represented as a class with
optional initialize(Hash), start() and stop() methods, which should each return quickly.
• Typically will start a long-running loop in a thread and respond to external events.
• Configured via services: section in torquebox.yml
Thursday, March 10, 2011
config/torquebox.yml
Services
services: IrcBot: server: freenode.net channel: #torquebox publish: /topics/irc
MyMudServer:
SomeOtherService:
Thursday, March 10, 2011
app/services/my_service.rb
Services
class MyService def initialize(opts=) name = opts[:publish] @queue = Queue.new(name) end def start Thread.new run end def stop @done = true endend
Thursday, March 10, 2011
app/services/my_service.rb
Services
class MyService def initialize(opts=) name = opts[:publish] @queue = Queue.new(name) end def start Thread.new run end def stop @done = true endend
Thursday, March 10, 2011
app/services/my_service.rb
Services
class MyService def initialize(opts=) name = opts[:publish] @queue = Queue.new(name) end def start Thread.new run end def stop @done = true endend
Thursday, March 10, 2011
app/services/my_service.rb
Services
class MyService def initialize(opts=) name = opts[:publish] @queue = Queue.new(name) end def start Thread.new run end def stop @done = true endend
Thursday, March 10, 2011
app/services/my_service.rb
Services
class MyService def run until @done @queue.publish(Time.now) sleep(1) end endend
Thursday, March 10, 2011
app/services/my_service.rb
Services
class MyService def run until @done @queue.publish(Time.now) sleep(1) end endend
Thursday, March 10, 2011
Clusteringless failure faster
Thursday, March 10, 2011
out-of-the-box• JBoss provides
• session replication
• load-balanced messaging
• mod_cluster provides
• session affinity
• intelligent load-balanced web
• failover
Thursday, March 10, 2011
mod_cluster
A reverse proxy implemented as an Apache module with JBoss awareness. Constantly gathers load statistics and deployment availability for intelligent request distribution.
Thursday, March 10, 2011
mod_cluster
Thursday, March 10, 2011
mod_cluster
• Dynamic configuration
• Server-side load factor calculation
• Fine-grained web app lifecycle
• AJP (Apache JServ Protocol) is optional. HTTP[S] is also supported.
Thursday, March 10, 2011
Cachinghot off of the press!
Thursday, March 10, 2011
Caching• Infinispan cache store
• non-clustered:
• local
• clustered:
• invalidation
• replicated
• distributed
Thursday, March 10, 2011
config/application.rb
Caching
config.cache_store = :torque_box_store, :mode => :local
# or
config.cache_store = ActiveSupport::Cache::TorqueBoxStore.new( :mode => :local )
Thursday, March 10, 2011
Other Cool Stuffwell, we think it’s cool
Thursday, March 10, 2011
Cool Stuff
• StompBox - git based deploys
• BackStage - see behind the curtain
• Built in authentication
• Benchmarking/speed improvements
Thursday, March 10, 2011
Live Demowish me luck
Thursday, March 10, 2011
Resources
• http://torquebox.org
• #torquebox on freenode
• https://github.com/torquebox
• http://twitter.com/torquebox
• http://projectodd.org
• https://github.com/tobias/torquebox_rails_sample
Thursday, March 10, 2011
Thanks!questions?
Thursday, March 10, 2011