Permalink
Browse files

First draft of ControlTower announcement

git-svn-id: https://svn.macosforge.org/repository/ruby/MacRubyWebsite/trunk@4515 23306eb0-4c56-4727-a40e-e92c0eb68959
  • Loading branch information...
joshua.ballanco@apple.com
joshua.ballanco@apple.com committed Sep 14, 2010
1 parent 3da9ad7 commit 3bb2f455f3e42d48f90bbc988253e09720c18471
@@ -0,0 +1,74 @@
+---
+title: ControlTower
+created_at: 2010-09-16 11:57:25.075413 -04:00
+blog_post: true
+layout: blog_entry
+author: Joshua Ballanco
+filter:
+ - erb
+ - textile
+---
+<% @page[:excerpt] = capture_erb do %>
+We are pleased to announce the first version of ControlTower, a Rack-based web application server for Ruby. ControlTower can already run basic rack and Sinatra apps, but there are still a lot of features to add.
+<% end %>
+
+h3. "It's called ControlTower!":http://www.youtube.com/watch?v=QbdXt2K27NU
+
+Way back in the announcement for MacRuby 0.5, we cryptically mentioned that we had gotten a web server to run a basic Sinatra app. While that statement was true, the server we had wasn't even really alpha worthy. At that point, it was more about proof of concept. If you have been watching the subversion repository you might have noticed that a new top-level project appeared about 4 months ago. If you're subscribed to the mailing list, you probably have even seen a bit of discussion take place about this project, and yet we still weren't quite ready to announce it to the world. Well, that changes today!
+
+Today we are officially announcing version 0.1 of ControlTower, the Rack-based web app server for MacRuby.
+
+If you're a casual follower of MacRuby, here is what you need to know in a nut-shell:
+
+<div class="control-tower">
+* ControlTower is a Rack-based web application server, written from the ground for MacRuby
+* It takes advantage of MacRuby's ability to mix-n-match Cocoa APIs with Ruby, so it will (for the forseable future) _only_ run on MacRuby
+* It can be used on its own or with a reverse proxy to serve any Rack-based web app whose libraries are supported by MacRuby (i.e. Sinatra, but not Rails...yet)
+* We are also interested in other non-traditional ways an embeddable Ruby web app server might be useful for native app development
+* It's small, it's light weight, and it's reasonably fast
+<div>
+<br />
+
+h3. How do I use it?
+
+To get ControlTower, you can checkout the source using subversion at @http://svn.macosforge.org/repository/ruby/ControlTower/tags/0.1@. Once you have the source you can use rake to build the gem (requires developer tools) and macgem to install like so:
+
+<pre class="commands">
+$ rake gem
+$ sudo macgem install pkg/control_tower-0.1-universal-darwin-10.gem
+</pre>
+
+There are two basic ways to interact with a Rack-based web server: create a rack-up file, or use a Rack::Handler in your code. Currently, both of these mechanisms work with ControlTower. Using a rack-up file is probably the simplest and most straight forward way to get up and running, and we've included a number of sample rack-up files in the "sample" directory of the repository. Once you have built and installed the ControlTower gem, you can use the @control_tower@ command to run any rack-up config:
+
+<pre class="commands">
+$ control_tower -R sample/simple_hello.ru
+You are cleared for take-off!
+Listening on 0.0.0.0:3000
+</pre>
+
+Alternatively, if you would like to start up the ControlTower server from within your code, you can use the @Rack::Handler::ControlTower@ class included with the ControlTower gem. This class has a single @run@ method that takes a rack "app" object and an options hash as its arguments. The options hash can be used to set the same server parameters as the command line tool. So, for example you can do:
+
+<%- coderay :lang => 'ruby' do -%>
+app = MyApp.new
+Rack::Handle::ControlTower.run(app, {:port => 80,
+ :host => 'myserver.com',
+ :concurrent => true })
+<%- end -%>
+
+Though, keep in mind that this method will block untill the server stops running, so if you want to do something else while the server is running you should put this code in a thread.
+<br />
+
+h3. What's in a Web Server?
+
+In general, all Ruby web app servers consist of the same three components: a socket manager, a header parser, and a request handler. Incoming requests initially encounter the socket manager which begins receiving data from the incoming connection. This data is then fed to the header parser until all of the headers have been received. These headers, along with any request body data (e.g. a form being POSTed), are then passed on to the request handler. The request handler makes any necessary changes on the server, gathers any data needed for a reply, and then sends that reply back to the socket manager which will send the reply back to the client.
+
+Ever since Mongrel, just about every Ruby web app server has used Zed Shaw's Ragel-based HTTP parser to parse headers on incoming requests, and ControlTower does too. Since the appearance of Rack, servers can count on an "app" object provided by a web app framework to handle the requests, in accordance with the Rack spec, and being a Rack-based server ControlTower relies on this as well. That leaves the socket manager as the only one of the three components that will differ considerably between servers. In the case of Thin the socket manager is an EventMachine event loop. In the case of Unicorn sockets are managed using a prefork mechanism. In ControlTower, we do our socket management with Grand Central Dispatch.
+
+The way this works is that each new incoming request is asynchronously dispatched to a GCD queue to be parsed and handled. In the default case, this queue is a serial queue, so requests are handled first-in first-out. By placing incoming requests onto a queue immediately, the server is quickly able to accept the next incoming request. If the @-c@ switch is used with the control_tower command or the @:concurrent@ key is set to true in the handler's options hash, ControlTower will use a concurrent GCD queue in place of the serial one. This means that ControlTower can handle multiple requests concurrently inside a single process; up to 75 at once on an 8-core MacPro (compared to 20 simultaneous requests per Thin process in threaded mode). If you want to give concurrent mode a try, just make sure that your web app and database layer are truly thread-safe, and not just green-thread-safe.
+<br />
+
+h3. How can I help?
+
+Glad you asked! ControlTower is still a relatively young project, so there is still lots to do. Right now, it is a small, robust server capable of handling moderate loads, but it doesn't have as many features as other Rack-based servers like Thin or Unicorn. Most notably, we do not yet support keep-alive. Other wish-list items include the addition of Rack adapters for the various common Ruby web app frameworks, support for unix domain sockets, and the ability to do Web Sockets.
+
+Of course, you don't have to be heavy into server development to lend a hand. We could use a lot of help just with testing and documentation (both of which are lacking currently). Perhaps the simplest and most important thing you can do to help is to try it out and send in your bug reports and feature requests. We started building ControlTower for our own purposes, but now we're ready to share it with the community and see where you take it.
@@ -0,0 +1,22 @@
+---
+title: 08
+created_at: 2010-08-09 00:57:24.985737 -04:00
+filter: erb
+dirty: true
+---
+<h2><%= h(@page.title) %></h2>
+
+<%
+ articles = @pages.find(:all, :in_directory => @page.dir, :recursive => true,
+ :sort_by => "created_at", :reverse => true, :blog_post => true)
+ articles.delete(@page)
+ paginate(articles, 10) do |page|
+-%>
+<div class="article">
+ <h1><%= link_to_page(page) %><span class="date">(<%= page.created_at.strftime('%Y-%m-%d') %>)</span></h1>
+
+ <div class="body">
+ <%= render(page) %>
+ </div>
+</div>
+<% end -%>
View
@@ -5,6 +5,16 @@ body {
color: #333;
}
+em {
+ font-style: italic;
+}
+
+li {
+ list-style-position: outside;
+ list-style-type: disc;
+ margin-left: 32px;
+}
+
#logo {
width=300px;
}
@@ -26,7 +26,7 @@ h3. Queues: The What and the Why
Queues, represented in MacRuby by the @Dispatch::Queue@ class, are data structures that execute tasks. Under the hood, GCD maintains a pool of POSIX threads to which queues dispatch their tasks; GCD will grow and shrink this pool dynamically and distribute its threads evenly among available processors.
Queues can execute their tasks either concurrently or sequentially. All queues begin executing tasks in the order in which they were received, but concurrent queues can run many tasks at once, whereas serial queues wait for one to complete before starting the next. GCD provides three singleton concurrent queues and allows the creation any number of serial queues. Performing work on a queue is extremely easy:
-<pre class="commands">
+<%- coderay :language => 'ruby' do -%>
# Create a new serial queue.
queue = Dispatch::Queue.new('org.macruby.examples.gcd')
# Synchronously dispatch some work to it.
@@ -41,7 +41,7 @@ queue.async do
sleep 1.0
puts 'Done!'
end
-</pre>
+<%- end -%>
If you paste this code into a running @macirb@ prompt, you’ll see that the queue blocks until the task specified in the @#sync@ block is finished, while task we specified in the block we passed to the @#async@ method is executed asynchronously in the background.
@@ -51,7 +51,7 @@ h3. A Real-Life Use Case: Synchronization
Ensuring that methods and data are accessed by one and only one thread at a time is a common problem in software development today. However, unlike languages such as Java and Objective-C, Ruby has no built-in language support for synchronization, relying instead on the Mutex and Monitor classes. However, GCD introduces another elegant idiom for synchronization that is higher-level than Mutex and significantly simpler than Monitor:
-<pre class="commands">
+<%- coderay :language => 'ruby' do -%>
class MissileLauncher
def initialize
@queue = Dispatch::Queue.new('org.macruby.synchronizer')
@@ -65,7 +65,7 @@ class MissileLauncher
end
end
end
-</pre>
+<%- end -%>
h3. Synchronization with Groups
@@ -75,7 +75,7 @@ h3. Groups in Action: Futures
Languages like "Io":http://www.iolanguage.com/ and "Oz":http://www.mozart-oz.org/ provide the notion of "futures":http://en.wikipedia.org/wiki/Futures_and_promises: proxy objects that perform expensive computations in the background. By using GCD queues to execute the tasks and groups to synchronize the tasks’ execution, we have a simple, concise and reliable implementation of futures in MacRuby:
-<pre class="commands">
+<%- coderay :laungage => 'ruby' do -%>
include Dispatch
class Future
def initialize(&block)
@@ -93,24 +93,25 @@ class Future
@value
end
end
-</pre>
+<%- end -%>
+
Now it’s easy to schedule long-running tasks in the background:
-<pre class="commands">
+<%- coderay :language => 'ruby' do -%>
some_result = Future.new do
p 'Engaging delayed computation!'
sleep 2.5
:done # Your result would go here.
end
-</pre>
+<%- end -%>
Accessing the value is as easy as calling @some_result.value@.
h3. Parallelization and Synchronization
Now let’s see an example of how easy it is to parallelize your code with the GCD’s groups and concurrent queues:
-<pre class="commands">
+<%- coderay :language => 'ruby' do -%>
class Array
def parallel_map(&block)
result = []
@@ -131,7 +132,7 @@ class Array
result
end
end
-</pre>
+<%- end -%>
This example uses the queue accessed through @Dispatch::Queue.concurrent@ to speed up @Array#map@ by spreading out the total work across the system’s available processors. From a two-core Macbook Air to a 16-core Mac Pro, GCD executes the tasks dispatched on the concurrent queue across all available processors. With fewer than a dozen lines of code, we’ve parallelized @#map@ and avoided race conditions by using groups to synchronize.
Oops, something went wrong.

0 comments on commit 3bb2f45

Please sign in to comment.