oscon 2010

62
Saturday, July 24, 2010

Upload: john-woodell

Post on 10-May-2015

3.033 views

Category:

Documents


2 download

TRANSCRIPT

Saturday, July 24, 2010

Ruby on Mirah on App EngineRun your apps on Google Servers, with access to first-class Java APIs

John WoodellCharles NutterJuly 22, 2010

2

Saturday, July 24, 2010

Google App Engine3

Saturday, July 24, 2010

• No need to install or maintain your own stack• Use Google scalable services via standard APIs• Built-in application management console

Key Features

4

• Pay-as-you-go, with free quota to get started

Saturday, July 24, 2010

• No native code• No threads or sockets• No writing to the filesystem

Key Limitations

5

• No more than 30 seconds per request

Saturday, July 24, 2010

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

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

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 users50000/day to admins

$0.0001/email

8

Saturday, July 24, 2010

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

JRuby on App Engine10

Saturday, July 24, 2010

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

11

• Spin-up new instances quickly using Mirah/Java servlets

Saturday, July 24, 2010

App Engine JRuby Milestones

12

• 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

Saturday, July 24, 2010

• Several seconds to “spin-up” a new JRuby instance• Some gems may need their extensions ported to Java• Not officially supported

Current Issues with JRuby on App Engine

13

+ , but you have all that you need

Saturday, July 24, 2010

14

Install it Now

sudo gem install google-appengine

Everything you need installs as gems

Saturday, July 24, 2010

App Engine Gems

15

• Development Gems–appengine-sdk–appengine-tools . . . dev_appserver.rb & appcfg.rb• Runtime Gems

– appengine-rack . . . . jruby-jars & jruby-rack–appengine-apis

• Related Gems–dm-appengine– rails_appengine– rails_dm_datastore– rails_tiny_ds

Saturday, July 24, 2010

App Engine JRuby APIs

• AppEngine::Users• AppEngine::Datastore• AppEngine::Memcache• AppEngine::Mail• AppEngine::URLFetch• AppEngine::Images• AppEngine::Logger• AppEngine::XMPP• AppEngine::Labs::TaskQueue• AppEngine::OAuth

16

• AppEngine::Blobstore

Saturday, July 24, 2010

17

MirahCharles Nutter

Saturday, July 24, 2010

Me

• Charles Oliver Nutter

• JRuby co-lead

• Ex-Java EE developer

• @headius

[email protected]

• blog.headius.com

Saturday, July 24, 2010

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

My Problem

• I love Ruby

• I write Java all day for JRuby

• How can I write Ruby all day?

Saturday, July 24, 2010

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

...Could Be Thisclass Foo def initialize(a) @a = a end

def show puts @a endend

Saturday, July 24, 2010

Mirahclass Foo def initialize(a:int) @a = a end

def show puts @a endend

Saturday, July 24, 2010

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

Features From Ruby

• Optional arguments ✓

• Internal iteration ✓

• Closures ✓

• Literals ✓

• String interpolation ✓

• Mixins, “open” classes (soon)

Saturday, July 24, 2010

Ruby

puts “Hello, world!”

Saturday, July 24, 2010

Mirah

puts “Hello, world!”

Saturday, July 24, 2010

Ruby public static __file__(Lruby/__dash_e__;Lorg/jruby/runtime/ThreadContext;Lorg/jruby/runtime/builtin/IRubyObject;[Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/Block;)Lorg/jruby/runtime/builtin/IRubyObject; @Lorg/jruby/anno/JRubyMethod;(name="__file__", frame=true, required=0, optional=0, rest=-2) L0 LINENUMBER 1 L0 ALOAD 1 ICONST_0 INVOKESTATIC ruby/__dash_e__.setPosition (Lorg/jruby/runtime/ThreadContext;I)V ALOAD 0 INVOKEVIRTUAL ruby/__dash_e__.getCallSite0 ()Lorg/jruby/runtime/CallSite; ALOAD 1 ALOAD 2 ALOAD 2 ALOAD 0 ALOAD 1 GETFIELD org/jruby/runtime/ThreadContext.runtime : Lorg/jruby/Ruby; INVOKEVIRTUAL ruby/__dash_e__.getString0 (Lorg/jruby/Ruby;)Lorg/jruby/RubyString; INVOKEVIRTUAL org/jruby/runtime/CallSite.call (Lorg/jruby/runtime/ThreadContext;Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/builtin/IRubyObject;)Lorg/jruby/runtime/builtin/IRubyObject; ARETURN

Saturday, July 24, 2010

Mirah

public static void main(java.lang.String[]); Code: 0: getstatic #12; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #14; //String Hello, world! 5: invokevirtual #20; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: return

Saturday, July 24, 2010

Mirah

// Generated from DashEpublic class DashE extends java.lang.Object { public static void main(java.lang.String[] argv) { java.io.PrintStream temp$1 = java.lang.System.out; temp$1.println("Hello, world!"); }}

Saturday, July 24, 2010

Ruby

def fib(a) if a < 2 a else fib(a - 1) + fib(a - 2) endend

Saturday, July 24, 2010

Mirah

def fib(a:int) if a < 2 a else fib(a - 1) + fib(a - 2) endend

Saturday, July 24, 2010

Ruby public static method__0$RUBY$fib(Lruby/__dash_e__;Lorg/jruby/runtime/ThreadContext;Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/Block;)Lorg/jruby/runtime/builtin/IRubyObject; @Lorg/jruby/anno/JRubyMethod;(name="fib", frame=true, required=1, optional=0, rest=-1) ALOAD 3 ASTORE 9 L0 LINENUMBER 1 L0 ALOAD 1 ICONST_0 INVOKESTATIC ruby/__dash_e__.setPosition (Lorg/jruby/runtime/ThreadContext;I)V ALOAD 0 INVOKEVIRTUAL ruby/__dash_e__.getCallSite0 ()Lorg/jruby/runtime/CallSite; ALOAD 1 ALOAD 2 ALOAD 9 LDC 2 INVOKEVIRTUAL org/jruby/runtime/CallSite.call (Lorg/jruby/runtime/ThreadContext;Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/builtin/IRubyObject;J)Lorg/jruby/runtime/builtin/IRubyObject; INVOKEINTERFACE org/jruby/runtime/builtin/IRubyObject.isTrue ()Z IFEQ L1 ALOAD 9 GOTO L2 L1 FRAME FULL [ruby/__dash_e__ org/jruby/runtime/ThreadContext org/jruby/runtime/builtin/IRubyObject org/jruby/runtime/builtin/IRubyObject org/jruby/runtime/Block T T T T org/jruby/runtime/builtin/IRubyObject] [] ALOAD 0 INVOKEVIRTUAL ruby/__dash_e__.getCallSite1 ()Lorg/jruby/runtime/CallSite; ALOAD 1 ALOAD 2 ALOAD 0 INVOKEVIRTUAL ruby/__dash_e__.getCallSite2 ()Lorg/jruby/runtime/CallSite; ALOAD 1 ALOAD 2 ALOAD 2 ALOAD 0 INVOKEVIRTUAL ruby/__dash_e__.getCallSite3 ()Lorg/jruby/runtime/CallSite; ALOAD 1 ALOAD 2 ALOAD 9 LDC 1 INVOKEVIRTUAL org/jruby/runtime/CallSite.call (Lorg/jruby/runtime/ThreadContext;Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/builtin/IRubyObject;J)Lorg/jruby/runtime/builtin/IRubyObject; INVOKEVIRTUAL org/jruby/runtime/CallSite.call (Lorg/jruby/runtime/ThreadContext;Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/builtin/IRubyObject;)Lorg/jruby/runtime/builtin/IRubyObject; ALOAD 0 INVOKEVIRTUAL ruby/__dash_e__.getCallSite4 ()Lorg/jruby/runtime/CallSite; ALOAD 1 ALOAD 2 ALOAD 2 ALOAD 0 INVOKEVIRTUAL ruby/__dash_e__.getCallSite5 ()Lorg/jruby/runtime/CallSite; ALOAD 1 ALOAD 2 ALOAD 9 LDC 2 INVOKEVIRTUAL org/jruby/runtime/CallSite.call (Lorg/jruby/runtime/ThreadContext;Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/builtin/IRubyObject;J)Lorg/jruby/runtime/builtin/IRubyObject; INVOKEVIRTUAL org/jruby/runtime/CallSite.call (Lorg/jruby/runtime/ThreadContext;Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/builtin/IRubyObject;)Lorg/jruby/runtime/builtin/IRubyObject; INVOKEVIRTUAL org/jruby/runtime/CallSite.call (Lorg/jruby/runtime/ThreadContext;Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/builtin/IRubyObject;Lorg/jruby/runtime/builtin/IRubyObject;)Lorg/jruby/runtime/builtin/IRubyObject; L2 FRAME SAME1 org/jruby/runtime/builtin/IRubyObject ARETURN

Saturday, July 24, 2010

Mirahpublic static int fib(int); Code: 0: iload_0 1: iconst_2 2: if_icmplt 9 5: iconst_0 6: goto 10 9: iconst_1 10: ifeq 17 13: iload_0 14: goto 30 17: iload_0 18: iconst_1 19: isub 20: invokestatic #10; //Method fib:(I)I 23: iload_0 24: iconst_2 25: isub 26: invokestatic #10; //Method fib:(I)I 29: iadd 30: ireturn

Saturday, July 24, 2010

Mirah

// Generated from DashEpublic 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

Ruby

def foo(a = 1, b = 2) puts a + bend

Saturday, July 24, 2010

Mirah

def foo(a:int = 1, b:int = 2) puts a + bend

Saturday, July 24, 2010

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

Ruby

a = [5,4,3,2,1]a.each do |x| puts xend

Saturday, July 24, 2010

Mirah

a = [5,4,3,2,1]a.each do |x| puts xend

Saturday, July 24, 2010

Mirah// Generated from DashEpublic 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

Ruby

t = Thread.new do puts “in thread”end

Saturday, July 24, 2010

Mirah

t = Thread.new do puts “in thread”end

Saturday, July 24, 2010

Mirah// Generated from DashEpublic 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

Mirah// Generated from DashEpublic 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

Mirah// Generated from DashEpublic 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

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

But It Feels Like Ruby!

• Clean, lightweight syntax

• Iteration, closures

• Far less “ceremony” than Java

• Performance equivalent to Java

Saturday, July 24, 2010

mirah.org

Saturday, July 24, 2010

50

Rails & Mirah DemosJohn Woodell

Saturday, July 24, 2010

Saturday, July 24, 2010

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

Saturday, July 24, 2010

Mirah apps should look familiar to Rubyists

Saturday, July 24, 2010

Mirah apps can use ERb templates

Saturday, July 24, 2010

The generated Java source can be inspected

Saturday, July 24, 2010

The ERb is transformed into method calls

Saturday, July 24, 2010

Your model definition is very concise

Saturday, July 24, 2010

Code is generated based on properties you define

Saturday, July 24, 2010

All the basic methods you need are generated

Saturday, July 24, 2010

Resources

• Blog– http://jruby-appengine.blogspot.com

• Code Site– http://code.google.com/p/appengine-jruby

• Examples Apps– http://rails-primer.appspot.com– http://dubious-demo.appspot.com

• Mirah Projects– http://github.com/headius/mirah– http://github.com/mirah/dubious

61

Saturday, July 24, 2010

Saturday, July 24, 2010