How to Troubleshoot Apps for the Modern Connected Worker
UCLUG TorqueBox - 03/08/2011
1. Toby Crawley
UCLUG
Creative Commons BY-SA 3.0
March 2011
Thursday, March 10, 2011
2. 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
3. Agenda
• High-level structure and TorqueBox
setup
• Web, Messaging, Scheduling,
Services, Clustering
Thursday, March 10, 2011
4. TorqueBox
the power of JBoss with the expressiveness of Ruby
Thursday, March 10, 2011
5. 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
6. 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
7. JRuby
a good idea done well
Thursday, March 10, 2011
8. JRuby: why?
• Very fast runtime
• Real threads
• Java libraries
• Java tools
• Healthy community
Thursday, March 10, 2011
9. JRuby: why not?
• Slower start up
• Native gems
• FFI
• C extension support
• Some Ruby libs not thread-safe
Thursday, March 10, 2011
10. JBoss AS
the enterprisey good parts
Thursday, March 10, 2011
11. I promise...
• No XML
• No Java *
• No war files *
• Only Ruby and YAML
* Unless you really want to
Thursday, March 10, 2011
12. 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
13. 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
14. Hot Deployment
$JBOSS_HOME/server/default/deploy/
• 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
Thursday, March 10, 2011
15. Hot Deployment
$JBOSS_HOME/server/default/deploy/
• anything added to deploy/
will get deployed
deployment
• anything removed from
descriptors
deploy/ will get
undeployed
• anything updated in
deploy/ will get redeployed
• TorqueBox deployers
make JBoss grok YAML
and ruby archives
Thursday, March 10, 2011
16. Hot Deployment
$JBOSS_HOME/server/default/deploy/
• anything added to deploy/
will get deployed
deployment
• anything removed from
descriptors
deploy/ will get
undeployed
• anything updated in
deploy/ will get redeployed
• TorqueBox deployers
make JBoss grok YAML
and ruby archives
Thursday, March 10, 2011
17. Hot Deployment
$JBOSS_HOME/server/default/deploy/
• anything added to deploy/
will get deployed
• anything removed from
deploy/ will get
undeployed
zip files
• anything updated in
(archives)
deploy/ will get redeployed
• TorqueBox deployers
make JBoss grok YAML
and ruby archives
Thursday, March 10, 2011
18. Hot Deployment
$JBOSS_HOME/server/default/deploy/
• anything added to deploy/
will get deployed
• anything removed from
deploy/ will get
undeployed
zip files
• anything updated in
(archives)
deploy/ will get redeployed
• TorqueBox deployers
make JBoss grok YAML
and ruby archives
Thursday, March 10, 2011
23. easy install
$ wget http://torquebox.org/torquebox-dev.zip
$ unzip torquebox-dev.zip Make sure the jruby
found in your path is in
$JRUBY_HOME/bin.
$ 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
24. easy install
$ wget http://torquebox.org/torquebox-dev.zip
$ unzip torquebox-dev.zip Make sure the jruby
found in your path is in
$JRUBY_HOME/bin.
$ 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
26. rake tasks
Rakefile
require "torquebox-rake-support"
Thursday, March 10, 2011
27. 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
28. 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
29. deployment descriptors
torquebox:deploy creates
a deployment descriptor in the
JBoss deploy/ directory
Thursday, March 10, 2011
30. deployment descriptors
deploy/myapp-knob.yml
application:
root: /path/to/myapp
env: development
web:
context: myapp
host: www.yourhost.com
static: public
rackup: config.ru
environment:
MAIL_HOST: mail.yourhost.com
REPLY_TO: you@yourhost.com
Thursday, March 10, 2011
31. deployment descriptors
deploy/myapp-knob.yml
application:
root: /path/to/myapp
env: development
web: The fully-qualified
context: myapp
host: www.yourhost.com
path to the app.
static: public This will be the value
environment: of either
RAILS_ROOT or
MAIL_HOST: mail.yourhost.com
REPLY_TO: you@yourhost.com RACK_ROOT
Thursday, March 10, 2011
32. deployment descriptors
deploy/myapp-knob.yml
application:
root: /path/to/myapp
env: development
web: The fully-qualified
context: myapp
host: www.yourhost.com
path to the app.
static: public This will be the value
environment: of either
RAILS_ROOT or
MAIL_HOST: mail.yourhost.com
REPLY_TO: you@yourhost.com RACK_ROOT
Thursday, March 10, 2011
33. deployment descriptors
deploy/myapp-knob.yml
application:
root: /path/to/myapp
env: development
web:
context: myapp The runtime mode of
host: www.yourhost.com
static: public
the app. This will be
environment: either RAILS_ENV
or RACK_ENV
MAIL_HOST: mail.yourhost.com
REPLY_TO: you@yourhost.com
Thursday, March 10, 2011
34. deployment descriptors
deploy/myapp-knob.yml
application:
root: /path/to/myapp
env: development
web:
context: myapp The runtime mode of
host: www.yourhost.com
static: public
the app. This will be
environment: either RAILS_ENV
or RACK_ENV
MAIL_HOST: mail.yourhost.com
REPLY_TO: you@yourhost.com
Thursday, March 10, 2011
35. deployment descriptors
The app’s context path
deploy/myapp-knob.yml “sub URI”):
(or
http://localhost:8080/myapp
application: Can be set via rake:
root: rake torquebox:deploy[myapp]
/path/to/myapp
env: development The default is root:
web: http://localhost:8080/
context: myapp
host: www.yourhost.com
static: public
environment:
MAIL_HOST: mail.yourhost.com
REPLY_TO: you@yourhost.com
Thursday, March 10, 2011
36. deployment descriptors
The app’s context path
deploy/myapp-knob.yml “sub URI”):
(or
http://localhost:8080/myapp
application: Can be set via rake:
root: rake torquebox:deploy[myapp]
/path/to/myapp
env: development The default is root:
web: http://localhost:8080/
context: myapp
host: www.yourhost.com
static: public
environment:
MAIL_HOST: mail.yourhost.com
REPLY_TO: you@yourhost.com
Thursday, March 10, 2011
37. deployment descriptors
deploy/myapp-knob.yml
application:
A list of virtual
root: /path/to/myapp
env: development
hostnames to which
web: to bind the app.
context: myapp
host: www.yourhost.com
static: public
environment:
MAIL_HOST: mail.yourhost.com
REPLY_TO: you@yourhost.com
Thursday, March 10, 2011
38. deployment descriptors
deploy/myapp-knob.yml
application:
A list of virtual
root: /path/to/myapp
env: development
hostnames to which
web: to bind the app.
context: myapp
host: www.yourhost.com
static: public
environment:
MAIL_HOST: mail.yourhost.com
REPLY_TO: you@yourhost.com
Thursday, March 10, 2011
39. deployment descriptors
deploy/myapp-knob.yml
application:
root: /path/to/myapp
env: development The location of the
web: app’s static
context: myapp content, either
host: www.yourhost.com
absolute or relative
static: public
environment: to the app’s root.
MAIL_HOST: mail.yourhost.com
REPLY_TO: you@yourhost.com
Thursday, March 10, 2011
40. deployment descriptors
deploy/myapp-knob.yml
application:
root: /path/to/myapp
env: development The location of the
web: app’s static
context: myapp content, either
host: www.yourhost.com
absolute or relative
static: public
environment: to the app’s root.
MAIL_HOST: mail.yourhost.com
REPLY_TO: you@yourhost.com
Thursday, March 10, 2011
41. deployment descriptors
deploy/myapp-knob.yml
application:
root: /path/to/myapp Any environment
env: development
web: variables required
context: myapp by the app.
host: www.yourhost.com
static: public
environment:
MAIL_HOST: mail.yourhost.com
REPLY_TO: you@yourhost.com
Thursday, March 10, 2011
42. deployment descriptors
deploy/myapp-knob.yml
application:
root: /path/to/myapp Any environment
env: development
web: variables required
context: myapp by the app.
host: www.yourhost.com
static: public
environment:
MAIL_HOST: mail.yourhost.com
REPLY_TO: you@yourhost.com
Thursday, March 10, 2011
43. 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
44. Web
make rack, not war
Thursday, March 10, 2011
45. 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
52. TorqueBox::Messaging
• JMS (Java Message Service)
is an API for messaging
• implementation
HornetQ is the JBoss JMS
Thursday, March 10, 2011
53. 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
54. Tasks
app/tasks/email_task.rb
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
end
end
Thursday, March 10, 2011
55. Tasks
app/tasks/email_task.rb
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
end
end
Thursday, March 10, 2011
56. Tasks
app/tasks/email_task.rb
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
end
end
Thursday, March 10, 2011
57. Tasks
app/tasks/email_task.rb
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
end
end
Thursday, March 10, 2011
58. Tasks
app/controllers/people_controller.rb
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
end
end
Thursday, March 10, 2011
59. Tasks
app/controllers/people_controller.rb
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
end
end
Thursday, March 10, 2011
60. Tasks
Call them from your
controllers, models, and
observers, or even other
tasks. Even in non-Rails
apps!
Thursday, March 10, 2011
61. Backgroundable
Inspired by DelayedJob’s
handle_asynchronously,
it’s trivial to create implicit
background Tasks.
Thursday, March 10, 2011
62. Backgroundable
lib/something.rb
include TorqueBox::Messaging
class Something
include Backgroundable
always_background :foo
def foo;; end
def bar;; end
end
...
@something.foo
@something.background.bar
Thursday, March 10, 2011
63. Backgroundable
lib/something.rb
include TorqueBox::Messaging
class Something
include Backgroundable
always_background :foo
def foo;; end
def bar;; end
end
...
@something.foo
@something.background.bar
Thursday, March 10, 2011
64. Backgroundable
lib/something.rb
include TorqueBox::Messaging
class Something
include Backgroundable
always_background :foo
def foo;; end
def bar;; end
end
...
@something.foo
@something.background.bar
Thursday, March 10, 2011
65. Backgroundable
lib/something.rb
include TorqueBox::Messaging
class Something
include Backgroundable
always_background :foo
def foo;; end
def bar;; end
end
...
@something.foo
@something.background.bar
Thursday, March 10, 2011
66. Backgroundable
app/models/slow_poke.rb
class SlowPoke < ActiveRecord::Base
always_background :takes_forever
def takes_forever;; end
def might_take_awhile;; end
end
@slowpoke.takes_forever
@slowpoke.background.might_take_awhile
Thursday, March 10, 2011
67. 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
74. Processors
app/models/print_handler.rb
include TorqueBox::Messaging
class PrintHandler < MessageProcessor
def on_message(body)
puts "Processing #{body} of #{message}"
end
def configure(opts)
@color = opts['color']
end
end
Thursday, March 10, 2011
75. Queues (again)
But how do you send a
message?
Thursday, March 10, 2011
76. Queues
example
include TorqueBox::Messaging
questions = 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.receive
answers.publish Time.now
Thursday, March 10, 2011
77. Queues
example
include TorqueBox::Messaging
questions = 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.receive
answers.publish Time.now
Thursday, March 10, 2011
78. Queues
example
include TorqueBox::Messaging
questions = 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.receive
answers.publish Time.now
Thursday, March 10, 2011
79. Queues
example
include TorqueBox::Messaging
questions = 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.receive
answers.publish Time.now
Thursday, March 10, 2011
80. 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
81. Scheduling
get regular later
Thursday, March 10, 2011
82. Jobs
app/jobs/newsletter_sender.rb
class NewsletterSender
def run()
subscriptions = Subscription.find(:all)
subscriptions.each do |e|
send_newsletter( e )
end
end
end
Thursday, March 10, 2011
83. Jobs
config/torquebox.yml
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
84. Jobs
“Fire every half hour from 10am until 1pm
on the third Friday of each month”
0 */30 10-13 ? * FRI#3
Seconds Minutes Hours DOM Month DOW Year
1-7
1-12 1970-
1-31 SUN-
0-59 0-59 0-23 JAN- 2099
?LW SAT
DEC empty
?L#
Thursday, March 10, 2011
85. 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
86. Services
run along, lil’ daemon
Thursday, March 10, 2011
87. Services
Long-running, non-web
“daemons” that share the
runtime environment and
deployment lifecycle of
your app.
Thursday, March 10, 2011
88. 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
90. Services
app/services/my_service.rb
class MyService
def initialize(opts={})
name = opts[:publish]
@queue = Queue.new(name)
end
def start
Thread.new { run }
end
def stop
@done = true
end
end
Thursday, March 10, 2011
91. Services
app/services/my_service.rb
class MyService
def initialize(opts={})
name = opts[:publish]
@queue = Queue.new(name)
end
def start
Thread.new { run }
end
def stop
@done = true
end
end
Thursday, March 10, 2011
92. Services
app/services/my_service.rb
class MyService
def initialize(opts={})
name = opts[:publish]
@queue = Queue.new(name)
end
def start
Thread.new { run }
end
def stop
@done = true
end
end
Thursday, March 10, 2011
93. Services
app/services/my_service.rb
class MyService
def initialize(opts={})
name = opts[:publish]
@queue = Queue.new(name)
end
def start
Thread.new { run }
end
def stop
@done = true
end
end
Thursday, March 10, 2011
94. Services
app/services/my_service.rb
class MyService
def run
until @done
@queue.publish(Time.now)
sleep(1)
end
end
end
Thursday, March 10, 2011
95. Services
app/services/my_service.rb
class MyService
def run
until @done
@queue.publish(Time.now)
sleep(1)
end
end
end
Thursday, March 10, 2011
96. Clustering
less failure faster
Thursday, March 10, 2011
98. 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
104. Other Cool Stuff
well, we think it’s cool
Thursday, March 10, 2011
105. Cool Stuff
• StompBox - git based deploys
• BackStage - see behind the curtain
• Built in authentication
• Benchmarking/speed improvements
Thursday, March 10, 2011
106. Live Demo
wish me luck
Thursday, March 10, 2011