Crank Up Your Apps With
Jim Crossley
MagicRuby
Creative Commons BY-SA 3.0
Feb 2011
1
Jim who?
• “recovering java architect”
• java since ’96, ruby since ’06
• emacs and guitars since forever
• Red Hat Senior Engineer
• proud member of
2
TorqueBox: what?
• A “real” app server for Ruby
• Founded in 2008
• Bob’s “labor of love”
• 100% open-source, LGPL license
• Reflects a strong commitment to
Ruby from Red Hat
7
JBoss AS6
• Tomcat for web
• Infinispan for caching
• HornetQ for messaging
• Quartz for scheduling
• mod_cluster for clustering
21
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
22
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
23
Hot Deployment
$JBOSS_HOME/server/default/deploy/
• deployment
anything added to deploy/
will get deployed
descriptors
• anything removed from
deploy/ will get
undeployed
• anything updated in
deploy/ will get redeployed
• TorqueBox deployers
make JBoss grok YAML
and ruby archives
24
Hot Deployment
$JBOSS_HOME/server/default/deploy/
• anything added to deploy/
will get deployed
• anything removed from
deploy/ will get
undeployed
• anything updated in
zip files
deploy/ will get redeployed
• (archives)
TorqueBox deployers
make JBoss grok YAML
and ruby archives
25
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
30
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
33
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.
34
deployment descriptors
deploy/myapp-{rails,rack}.yml
application:
root: /path/to/myapp
env: development
web:
context: myapp The fully-qualified
host: www.yourhost.com path to the app.
static: public This will be the value
rackup: config.ru
environment: of either
RAILS_ROOT or
MAIL_HOST: mail.yourhost.com
REPLY_TO: you@yourhost.com RACK_ROOT
37
deployment descriptors
deploy/myapp-{rails,rack}.yml
application:
root: /path/to/myapp
env: development
web:
context: myapp
host: www.yourhost.comThe runtime mode of
static: public the app. This will be
rackup: config.ru
environment:
either RAILS_ENV
MAIL_HOST: mail.yourhost.comor RACK_ENV
REPLY_TO: you@yourhost.com
38
deployment descriptors
The app’s context path
deploy/myapp-{rails,rack}.yml
(or “sub URI”):
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
rackup: config.ru
environment:
MAIL_HOST: mail.yourhost.com
REPLY_TO: you@yourhost.com
39
deployment descriptors
deploy/myapp-{rails,rack}.yml
application:
root: /path/to/myapp A list of virtual
env: development hostnames to which
web: to bind the app.
context: myapp
host: www.yourhost.com
static: public
rackup: config.ru
environment:
MAIL_HOST: mail.yourhost.com
REPLY_TO: you@yourhost.com
40
deployment descriptors
deploy/myapp-{rails,rack}.yml
application:
root: /path/to/myapp
env: development
web:
The location of the
context: myapp app’s static
host: www.yourhost.com content, either
static: public absolute or relative
rackup: config.ru to the app’s root.
environment:
MAIL_HOST: mail.yourhost.com
REPLY_TO: you@yourhost.com
41
deployment descriptors
deploy/myapp-{rails,rack}.yml
application:
root: /path/to/myapp
env: development
web:
The name of the
context: myapp rackup script used to
host: www.yourhost.com boot your app
static: public
rackup: config.ru
environment:
MAIL_HOST: mail.yourhost.com
REPLY_TO: you@yourhost.com
42
deployment descriptors
deploy/myapp-{rails,rack}.yml
application:
root: /path/to/myapp
env: development Any environment
web: variables required
context: myapp by the app.
host: www.yourhost.com
static: public
rackup: config.ru
environment:
MAIL_HOST: mail.yourhost.com
REPLY_TO: you@yourhost.com
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
44
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
46
TorqueBox::Messaging
• No extra tables in your database
• No external system to manage
• Little to no config required at all
• No redeploy necessary in dev mode
• Efficient loading of rails environment
• Automatic load balancing and retries
• Works on Windows, if you care
54
Tasks
app/tasks/email_task.rb
class EmailTask < TorqueBox::Messaging::Task
def welcome(payload)
person = payload[:person]
person ||= Person.find_by_id(payload[:id])
if person
# send the email
person.welcomed = true
person.save!
end
end
end
55
Tasks
app/tasks/email_task.rb
class EmailTask < TorqueBox::Messaging::Task
def welcome(payload)
person = payload[:person]
person ||= Person.find_by_id(payload[:id])
if person
# send the email
person.welcomed = true
person.save!
end
end
end
56
Tasks
app/tasks/email_task.rb
class EmailTask < TorqueBox::Messaging::Task
def welcome(payload)
person = payload[:person]
person ||= Person.find_by_id(payload[:id])
if person
# send the email
person.welcomed = true
person.save!
end
end
end
57
Tasks
app/tasks/email_task.rb
class EmailTask < TorqueBox::Messaging::Task
def welcome(payload)
person = payload[:person]
person ||= Person.find_by_id(payload[:id])
if person
# send the email
person.welcomed = true
person.save!
end
end
end
58
Tasks
app/tasks/email_task.rb
class EmailTask < TorqueBox::Messaging::Task
def welcome(payload)
person = payload[:person]
person ||= Person.find_by_id(payload[:id])
if person
# send the email
person.welcomed = true
person.save!
end
end
end
59
Backgroundable
app/models/slow_poke.rb
class SlowPoke < ActiveRecord::Base
def takes_forever;; end
def might_take_awhile;; end
end
SlowPoke.always_background :takes_forever
@slowpoke.takes_forever
@slowpoke.background.might_take_awhile
68
Queues
Tasks are built on top of
Queues. Of course, you may
build your own “MOM” apps
by defining your own Queues,
Topics, and their message
Processors yourself.
69
Queues
example
include TorqueBox
req = Messaging::Queue.new '/queues/questions'
res = Messaging::Queue.new '/queues/answers'
Thread.new do
req.publish "What time is it?"
puts res.receive( :timeout => 1000 )
end
puts req.receive
res.publish Time.now
78
Queues
example
include TorqueBox
req = Messaging::Queue.new '/queues/questions'
res = Messaging::Queue.new '/queues/answers'
Thread.new do
req.publish "What time is it?"
puts res.receive( :timeout => 1000 )
end
puts req.receive
res.publish Time.now
79
Queues
example
include TorqueBox
req = Messaging::Queue.new '/queues/questions'
res = Messaging::Queue.new '/queues/answers'
Thread.new do
req.publish "What time is it?"
puts res.receive( :timeout => 1000 )
end
puts req.receive
res.publish Time.now
80
Queues
example
include TorqueBox
req = Messaging::Queue.new '/queues/questions'
res = Messaging::Queue.new '/queues/answers'
Thread.new do
req.publish "What time is it?"
puts res.receive( :timeout => 1000 )
end
puts req.receive
res.publish Time.now
81
Queues
“on the fly”
include TorqueBox
queue = Messaging::Queue.new '/queues/foo'
queue.create
...
queue.destroy
82
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.yml to define topics
• use TorqueBox::Messaging::Topic
83
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#
87
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.
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.yml
91
JBOSS_CONF
TorqueBox ships with two
JBoss server configurations:
default (not clustered) and all
(clustered). To enable
clustering...
$ export JBOSS_CONF=all
102
deploy and run
$ export JBOSS_CONF=all
$ jruby -S rake torquebox:deploy
$ jruby -S rake torquebox:run
103
mod_cluster
A reverse proxy implemented
as an Apache module with
JBoss awareness. Constantly
gathers load statistics and
deployment availability for
intelligent request distribution.
104
Future
• Performance benchmarking and
optimization
• Infinispan for ActiveSupport::Cache
and NoSQL persistence
• JBoss SSO, HASingleton, logging
• CDI injection of Java components into
Ruby
• More JavaEE bridged to Ruby where
it makes sense, e.g. BPM, Drools,
Transactions, etc.
108