The document provides information about running Ruby applications on Google App Engine using JRuby. It discusses key features and limitations of App Engine, how to set up the development environment, deploy apps, and pay-as-you-go billing. It also introduces Mirah as a way to write Java code using a Ruby-like syntax and compiles to Java bytecode.
2. Ruby on Mirah on App Engine
Run your apps on Google Servers,
with access to first-class Java APIs
John Woodell
Charles Nutter
July 22, 2010
2
Saturday, July 24, 2010
4. Key Features
• No need to install or maintain your own stack
• Use Google scalable services via standard APIs
• Built-in application management console
• Pay-as-you-go, with free quota to get started
4
Saturday, July 24, 2010
5. Key Limitations
• No native code
• No threads or sockets
• No writing to the filesystem
• No more than 30 seconds per request
5
Saturday, July 24, 2010
6. Dev AppServer
• Local implementation of services
– LRU memcache
– Disk-backed datastore
– HttpClient-backed URLFetch
• Emulates the production environment
– Sandbox restrictions may be inconsistent,
so run tests on production servers as well
6
Saturday, July 24, 2010
7. Deployment
• Your app lives at
– <app_id>.appspot.com, or
– Custom domain with Google Apps
• Deploying uploads
– Static files
– Resource files
– Other metadata (datastore indexes, cron jobs)
• Admin Console
– dashboards
– manage multiple versions
– view logs
7
Saturday, July 24, 2010
8. Quotas and Billing
Resource Provided Free Additional Cost
CPU time 6.5 hours/day $0.10/hour
Bandwidth In 1GByte/day $0.10/GByte
Bandwidth Out 1GByte/day $0.12/GByte
Stored Data 1 GB $0.005/GB-day
Emails sent 2000/day to users $0.0001/email
50000/day to admins
8
Saturday, July 24, 2010
9. App Engine Product Roadmap
• SSL for third-party domains
• Background servers capable of running for longer than 30s
• Ability to reserve instances to reduce application loading overhead
• Ability to select different availability vs. latency options for Datastore
• Support for mapping operations across datasets
• Datastore dump and restore facility
• Raise request/response size limits for some APIs
• Improved monitoring and alerting of application serving
• Support for Browser Push (Comet) communication
• Built-in support for OAuth & OpenID
9
Saturday, July 24, 2010
11. Benefits of JRuby
• Outperforms MRI in many cases... 2x to 10x
• Gem extensions written in Java (no more segfaults)
• A wealth of integration options and first-class Java APIs
• Spin-up new instances quickly using Mirah/Java servlets
11
Saturday, July 24, 2010
12. App Engine JRuby Milestones
• 2009-04-08 @olabini publishes blog post on YARBL
• 2009-04-09 @nicksieger publishes warbler demo
• 2009-05-06 RailsConf (sinatra & merb)
• 2009-11-02 0.0.5 bundler, precompilation & Duby preview
• 2009-11-20 RubyConf (Rails 3.0.pre & Duby App)
• 2009-12-27 @urekat publishes Rails 2.3.5 patches
• 2010-01-11 @codingforrent published rails/dm gem
• 2010-01-21 0.0.8 Rails 2.3.5 Primer for DM & TinyDS
• 2010-01-26 0.0.9 Mechanize and Hpricot demos
• 2010-02-27 0.0.10 ActionMailer, ImageService, jruby-openssl
• 2010-04-08 @azazeal blog post on taxster.gr (OpenID)
• 2010-06-09 0.0.14 JRuby 1.5.1 & app.yaml preview
12
Saturday, July 24, 2010
13. Current Issues with JRuby on App Engine
• Several seconds to “spin-up” a new JRuby instance
• Some gems may need their extensions ported to Java
• Not officially supported , but you have all that you need
+
13
Saturday, July 24, 2010
14. Install it Now
sudo gem install google-appengine
Everything you need installs as gems
14
Saturday, July 24, 2010
17. Mirah
Charles Nutter
17
Saturday, July 24, 2010
18. Me
• Charles Oliver Nutter
• JRuby co-lead
• Ex-Java EE developer
• @headius
• [email protected]
• blog.headius.com
Saturday, July 24, 2010
19. My Day Job
• JRuby and JRuby-related extensions
• JVM-based utilities and libraries (for JRuby?)
• Bytecode generation
• Mobile and embedded interests
• Narrow, “system”-level scope
Saturday, July 24, 2010
20. My Problem
• I love Ruby
• I write Java all day for JRuby
• How can I write Ruby all day?
Saturday, July 24, 2010
21. What If This...
public class Foo {
private int a;
public Foo(int a) {
this.a = a;
}
public void show() {
System.out.println(a);
}
}
Saturday, July 24, 2010
22. ...Could Be This
class Foo
def initialize(a)
@a = a
end
def show
puts @a
end
end
Saturday, July 24, 2010
23. Mirah
class Foo
def initialize(a:int)
@a = a
end
def show
puts @a
end
end
Saturday, July 24, 2010
24. Mirah
• A nicer way to write Java
• Ruby syntax with modifications
• Feels like Ruby
• Compiles to Java/JVM
• No runtime library
Saturday, July 24, 2010
35. Mirah
// Generated from DashE
public class DashE extends java.lang.Object {
public static void main(java.lang.String[] argv) {
}
public static int fib(int a) {
return (a < 2) ? (a) : ((DashE.fib((a - 1)) +
DashE.fib((a - 2))));
}
}
Saturday, July 24, 2010
36. Ruby
def foo(a = 1, b = 2)
puts a + b
end
Saturday, July 24, 2010
37. Mirah
def foo(a:int = 1, b:int = 2)
puts a + b
end
Saturday, July 24, 2010
38. Mirah
public static java.io.PrintStream foo(int a, int b) {
java.io.PrintStream temp$1 =
java.lang.System.out;
temp$1.println((a + b));
return temp$1;
}
public static java.io.PrintStream foo() {
return foo(1);
}
public static java.io.PrintStream foo(int a) {
return foo(a, 2);
}
Saturday, July 24, 2010
39. Ruby
a = [5,4,3,2,1]
a.each do |x|
puts x
end
Saturday, July 24, 2010
40. Mirah
a = [5,4,3,2,1]
a.each do |x|
puts x
end
Saturday, July 24, 2010
41. Mirah
// Generated from DashE
public class DashE extends java.lang.Object {
public static void main(java.lang.String[] argv) {
java.util.List a =
java.util.Collections.unmodifiableList(
java.util.Arrays.asList(1, 2, 3, 4, 5));
java.util.Iterator __xform_tmp_1 = a.iterator();
label1:
while (__xform_tmp_1.hasNext()) {
java.lang.Object x = __xform_tmp_1.next();
label2:
{
java.io.PrintStream temp$3 = java.lang.System.out;
temp$3.println(x);
}
}
}
}
Saturday, July 24, 2010
42. Ruby
t = Thread.new do
puts “in thread”
end
Saturday, July 24, 2010
43. Mirah
t = Thread.new do
puts “in thread”
end
Saturday, July 24, 2010
44. // Generated from DashE
Mirah
public class DashE extends java.lang.Object {
public static void main(java.lang.String[] argv) {
DashE.__xform_tmp_1 $binding = new DashE.__xform_tmp_1();
$binding.x = "in thread";
java.lang.Thread t = new java.lang.Thread(new DashE.__xform_tmp_2($binding));
}
public static class __xform_tmp_1 extends java.lang.Object {
java.lang.String x;
}
public static class __xform_tmp_2 extends java.lang.Object implements
java.lang.Runnable {
private DashE.__xform_tmp_1 binding;
public __xform_tmp_2(DashE.__xform_tmp_1 binding) {
this.binding = binding;
}
public void run() {
DashE.__xform_tmp_1 $binding = this.binding;
java.io.PrintStream temp$1 = java.lang.System.out;
temp$1.println($binding.x);
}
}
}
Saturday, July 24, 2010
45. // Generated from DashE
Mirah
public class DashE extends java.lang.Object {
public static void main(java.lang.String[] argv) {
DashE.__xform_tmp_1 $binding = new DashE.__xform_tmp_1();
$binding.x = "in thread";
java.lang.Thread t = new java.lang.Thread(new DashE.__xform_tmp_2($binding));
}
public static class __xform_tmp_1 extends java.lang.Object {
java.lang.String x;
}
public static class __xform_tmp_2 extends java.lang.Object implements
java.lang.Runnable {
private DashE.__xform_tmp_1 binding;
public __xform_tmp_2(DashE.__xform_tmp_1 binding) {
this.binding = binding;
}
public void run() {
DashE.__xform_tmp_1 $binding = this.binding;
java.io.PrintStream temp$1 = java.lang.System.out;
temp$1.println($binding.x);
}
}
}
Saturday, July 24, 2010
46. // Generated from DashE
Mirah
public class DashE extends java.lang.Object {
public static void main(java.lang.String[] argv) {
DashE.__xform_tmp_1 $binding = new DashE.__xform_tmp_1();
$binding.x = "in thread";
java.lang.Thread t = new java.lang.Thread(new DashE.__xform_tmp_2($binding));
}
public static class __xform_tmp_1 extends java.lang.Object {
java.lang.String x;
}
public static class __xform_tmp_2 extends java.lang.Object implements
java.lang.Runnable {
private DashE.__xform_tmp_1 binding;
public __xform_tmp_2(DashE.__xform_tmp_1 binding) {
this.binding = binding;
}
public void run() {
DashE.__xform_tmp_1 $binding = this.binding;
java.io.PrintStream temp$1 = java.lang.System.out;
temp$1.println($binding.x);
}
}
}
Saturday, July 24, 2010
47. It’s Not Ruby
• Using Java’s libraries and type system
• No “eval”
• No runtime-mutable classes
• Ruby libraries will not work
Saturday, July 24, 2010
48. But It Feels Like Ruby!
• Clean, lightweight syntax
• Iteration, closures
• Far less “ceremony” than Java
• Performance equivalent to Java
Saturday, July 24, 2010
53. Benefits of Mirah on App Engine
• New instances always spin-up in about a second
• Dubious framework uses familiar Rails conventions
• Code in Java or Ruby when Mirah lacks features you require
• The generated Java source can be inspected at any time
53
Saturday, July 24, 2010