 Hello everybody. I'm John Waddell. Okay. I'm speaking too loud, huh? Welcome everybody. I'm John Waddell, and I'm here with Ryan Brown today. And we're talking about scaling your application on App Engine with Ruby and Doobie. So, we're going to talk about App Engine without any feedback, hopefully. First of all, what is App Engine? It is a cloud computing platform, and that means you can run your web app on Google's infrastructure. And Google spends a lot of time and energy figuring out how to build efficient hardware and data centers and also build applications that are available. And so, App Engine is a way for Google to provide some of that to you to build your application. And we also provide platform as a service. So, unlike some traditional hosting environments where you have, you know, infrastructure, a box and networking and load balancers and logging and all that, you basically just give us your code, we run it for you, we bring up as many instances as you need, and hopefully simplify quite a lot. And Ryan's going to talk about architecture. Right. So, when you have a request come into App Engine, the first thing that happens is it goes to like close school data center, travels through our network to get to the App Engine front-end. We've got load balancing here, so you don't have to worry about that. Your application is running on at least three app servers, so you've got automatic redundancy there. We automatically bring up more instances of your application as you're getting more traffic. Another feature of App Engine, you just pay for what you're using. You pay CPU as you're using. If you have your app sitting there idle, nobody's accessing it, you don't pay at all. Then each app server provides you access to a set of App Engine APIs. We don't allow you to open sockets or anything like that, so we provide you APIs for accessing the outside world. This is an example of one of our higher-profile applications we've had. In the beginning of the year, the president used this for a national on-TV White House event. So, you can see traffic is going along. Right here, right at the deadline where you could ask the president a question online, bikes up like twice the normal traffic. If you're using a normal provider, you would have to provision your servers to handle the 700 TPS the entire time you were at this ramp for three days. You'd have to have the 700 TPS provision the entire time and pay for those servers the whole time. Whereas with App Engine, you just pay for it for those 15 minutes while you were actually running the 700 TPS. So this is what we charge. It's free to get started. You could buy a bandwidth, you could buy a data, six and a half, a few hours for free. And then as you use beyond that, you pay, you set a daily budget if you will never charge you more than that. So if you run out of quota, your app will turn off. But we'll never charge you more than you ask for. And you also want to be careful about building an application that's not transferring, you know, you might have another paragraph somewhere else. If you transfer data in between our data center and your data center, that's, you're going to pay for that. But you might, you know, build an application that has data elsewhere and the client's bringing data into it so you can avoid that. So let's talk about JRuby on App Engine now. Or Ruby on App Engine. So we're using JRuby. As Charles just told us, Ruby on JRuby is fast. It is just Ruby. It is faster than the MRI 1.8 and maybe about as fast as 1.9. It's a nice garbage collection of other features. Also you have a wealth of integration options. And by that I mean there's all these Java libraries that you can just basically use from JRuby that are very nice. And also you have all of the supported App Engine APIs for Java. So Java is an officially supported platform. They're engineers Google working on it. All of those APIs are available to you. And there's not necessarily anything else you need in order to take advantage of them. So we like a small and modular framework. You can build a nice little rack application. I'll show you how to do that. You can, right now today, very easily build a Sinatra application because you want to load as little code as possible to respond to each request. And Sinatra does that nicely. If you're feeling kind of experimental, you could try using Merb or Rails. Right now, Rails 3 is not really released. So you have to experiment a little bit with pulling something off GitHub and try it out. And I'll show you a demo of that later. And also you have a doobie as an option and we'll show you that later. That's something that's not technically Ruby but is going to be very familiar to you. We also like data macro for persistence. Unlike Active Record where you create a model that is in some cases empty and there's some migration that describes your schema database and then the system synchronizes that. Your schema is actually in the model and there are no migrations. If you decide at some point, I want to add a new attribute to the model. You just store it in there and now all of a sudden you have records that are created with this new attribute. Hopefully your older records that don't have the attribute don't create an issue for you. But you can just put whatever attributes in there you want. Datastore is just going to persist those objects. There's no translation to SQL. There is no SQL. And you also have access to extensions like validations, Active Record finders like find all by first name, etc. You can use those. All the extensions should work fine even though some of the operators that we have are limited because Datastore is a very simple persistence layer. And also it works with the existing DM adapter for Datamapper that Ryan wrote. So you can start using it today. Okay, so it's very easy to install and these are our tools. You just sudo gem install Google App Engine and it brings down the whole development environment that we created and you should do it today and I'm going to have Ryan talk about some of the things that are there. Right, so well there's a bunch of gems to get installed when you install Google App Engine. We have App Engine Rack that's just our tool for integrating with Rack. That's how you configure App Engine. The tool that the Ruby SDK itself lets you run your app locally in the same environment as production. So you can test out all the APIs and everything and App Config is what you use for actually uploading your app. The App Engine SDK is actually the Java SDK, so we install that for you. You don't have to download it separately. And the App Engine JRuby jars, that's our package version of JRuby. So you run this all in MRI, we automatically start up JRuby for you at the right time so you don't have to worry about any of that. And then inside your application, we use Bumbler as you could have mentioned, we use Bumbler to package up all of your gems so that you're running your app locally with the exact environment that you will when you deploy it. And so you need to install into your bundled app the App Engine API and App Engine Rack again. Okay, we can talk about the API as you can. So as I said earlier, there's these Java APIs for App Engine and in some cases there are restrictions in App Engine like you're not allowed to talk to sockets or start threads or write files, things like that. So if you want a timer to time your URL and open a socket, well, there's a lot of things you can't do there. But we give you URL fetch API for that. We also have at the top this user API, you can just integrate with a Google account for authenticating users. You just say it requires login or it requires an administrator. And administrators are the people who are developers on your app. Require login is just anyone who has a Google account. So you don't create a database of users, you just use a Google account for that. The Datastore adapter, of course, is how we communicate with Datastore. We have an memcache adapter that is a lot like the memcache you're familiar with. It's modified a little bit more than App Engine. But you shouldn't really need to worry about how it's different. We have a mail API and I'll talk about XMPP API, Ryan's initial demo of that later. Those are incoming and outgoing APIs. The URL fetch API, as I said, is really designed so that you can just say I want this URL and it comes down to whether it's SSL or get or post. You don't worry about all the gory details of an HTTP like you would normally see. You just use our API and the URL comes down. We also have an images API that is, you know, the low level Java API. And we had a contributor that created a wrapper from Ruby to use that. And I'll show you a demo of that later. The logging API, of course, is used because you can't write files. So you use our logging API and then the logs show up in our logs. And this is a task for scheduling tasks. And I'll have Ryan talk about this demo here. So this was just a quick demo I wrote to, for example, using XMPP. So incoming messages, whether email or XMPP, get sent as a normal HTTP request to your application at a special URL. So you just need to define a handler for that URL and mark your application that you want to receive XMPP. This is so like somebody doesn't hack you by sending you thousands of XMPP messages and you're not even listening to them. You don't put this here, you won't ever get charged for XMPP messages. And so then in your handler we provide stuff for parsing the messages. So this is just a simple echo. It takes the message, sends it right back to you. And this is a figure U file that has a RAC application inside it with some RAC middleware. So you generally aren't going to build your whole application inside of your RAC file, but you can certainly do that. And I think that's a great way to get started as you want to know how the API works. You build up a little simple RAC file like this, try it locally, deploy it to the server, see that it works, and then you can start planning how you're going to actually build it into your application. Okay, so we're going to do a demo. We have a little bit of a connectivity issue here, but I'm going to try this anyway. So I've got this very simple hello RAC command, and this is what you would see in the RAC documentation. Okay, so I'm going to see where I'm here. Where's my N? There it is. Okay, so as you saw in that last screenshot, we have a lot of configuration to publish it. So where was I? I was typing a little application here. Okay, so we're going to say the response is okay. We don't need to worry about the headers because App Engine is going to figure out the content links and all that stuff for us. So we're just going to say hello. Hello RubyConf as a matter of fact. Now, so I have this one configure you file. If I run the dev app server and I tell it, please run on this current directory. It's going to see the configure you and say, ah, perfect, that's all I need. It's going to generate a gem file because I didn't have one and generally you're not going to do anything with that one. So it just created an empty gem jar for me. It also installed our version of JRuby that doesn't have Ruby gems in it because that's going to have a penalty associated with it and we don't need it. We also installed JRerac that allows our RAC application to communicate with the infrastructure on App Engine. And it generated the configuration files that are actually just XML files that you never need to look at or touch. In fact, if you modify them, we'll just blow away your changes. You just do all your changes and then configure you. I will show you that in a second. So if I say new here, hello RubyConf. So that is a very simple RAC application and deploying it to production is just telling it to update and I would say that in production. I can show that in a second. Okay, so can you hold that for me for a second? All right, so let's take a look at what we have here. I told it to run. I created a public folder. It probably created robots text and the icon for efficiency. I have it configure you. It created an empty gem file that looks like that. If I decide I want to run a Sinatra app, I'm just going to comment out those two things and then I'm ready to go. It also created a web directory and that has a couple XML files in it. If you really want to look at the XML files, you can. We allow you to insert additional things into the XML files by putting middleware in the configure you. But for most part, you should need to worry about that it gets started. So let's go back out here to a little more interesting example. I have a guest book. I'm going to look at this other app here that we have. If you want to run this yourself, you really just want to go to our blog or the code site. I have the browse source code link here or the blog. There's a demo. There's a Sinatra demo. The code I'm looking at is this one file here. It is a little guest book app. Just running through real quickly. I'm going to use DMCore. We have Datamapper. I'm using Sinatra. I'm going to connect the TAP engine. I also have one model here which has an ID and a message in it. That's really all there is to it. There's really no configuration to the database. There's no passwords or ports or hosts. It's just your app has a data store associated with it. You just don't worry about it. If you want to get data in and out of that app, you might build some code to give the data to you. But you really just don't worry about connectivity. We also are saying here that I want to map hosts and get to slash and either list all of the shouts or create a new one. What happens when I run that? Well, I'll do that right now. Again, I'm just going to run dev app server. In a second, it will be ready. We'll reload it. Here it comes. There it is. I wrote nothing. That is the simplest app that is putting data in the desk or pulling back out displaying it. Really not that exciting, but that's really all a web app is in this case. You want to have a specific player. You want to make it simple to create a new book. The other demo that I'm going to show you guys real quick is my Rails demo. As I said, it's a little early to be depending on that, but there's certainly something you can look at. There are a lot of conventions and shortcuts in Rails that people want to take advantage of. At this point, I guess I can talk about some of these concerns we've had and why we need Rails 3. Rails 2 really had tight integration with RubyGems. It was using RubyGems for doing a lot of things and managing your local gems and system gems. We really don't need any of that because it's a bit that we take on spinning up a new app that we really don't want to have. We're just using Bundler to figure out what the gems we need before we deploy. Then they deploy up here on your load path and then just run without all those RubyGems stuff. Rails 3 will actually function that way. If I reload here, I should get this app. I'll just basically bring up this little screen to show you what it's doing. Can you guys see that? Is that too small? I have a modified version of that properties info screen. I see that I'm running a new version of JRuby here because I've got 187. I told RubyGems that it was version 0000 because I thought maybe someone would ask for it and I'd put something there. But I don't even have RubyGems loaded. It's basically stubbed out. We also have Rack. I have a bunch of gems that I brought up at GitHub. Then down below that, I have some environment variables that I thought would be interesting from App Engine. I am in development mode. I've got a version of JRuby, JRack, the APIs, et cetera. It also says that my app is called Rails Primer and it's version 3. Let's take a look at some of those files real quick. My gem file looks like that. These three things at the top here you really don't want to mess with those but I've basically set my sources and I'm pulling something up GitHub. It's a little bit of an experimental situation to be pulling code right in and expect to work but you can certainly do it. We don't hinder that and if you want to work on free release code, your own code especially, you really want to have an repository because it's fun when you get it in some way. The configure you looks like this. I'm saying that it's version 3. I could also make this version 3.0.3 very easily. It doesn't matter if it could be version test. I can make that version of string or an integer. It will be converted to string. I also tell it that I want to exclude any of the files that are the Rails files that I don't need in production. This Rails exclude is just an array of things like don't give me all the directories that I need for testing but I don't actually need in production because every file you put in production should take time. I also tell it that I want to set my environment based on App Engine Rack environment and App Engine Rack is going to figure out whether I'm in production or development mode for me and that's really the only way you want to do that. Then you can do some things in production with testing and such properly. Also, of course, I require this environment and run Rails. Is there anything else interesting in here? That's basically it. As soon as Rails 3.0.3 gems are officially released, I imagine we'll flip a guide showing how to use it and you should be able to load a request with a lot less code than Rails 2.0 without using RubyGems. Then you can build parts of your apps in Rails and maybe other parts of your apps you want to optimize a little bit. We'll have Ryan talk a little bit about ways that you might optimize your app. We'll do that now. Let's talk about current issues. I've touched on these a little bit. These are really the main issues right now. The time to spin up a new instance of your application takes for that Sinatra guestbook just under 10 seconds. We're looking at ways to let JRuby work smarter and let App Engine work smarter with it so that we can reduce that. But basically that is an issue right now. Once your app is running and has traffic, the traffic is going to be responded to in milliseconds, but every so often as we add a new host, there might be a hit that someone takes. Also, some gem extensions aren't ported to Java yet. A lot have been. I can't see that Nick Seeger is taking care of Hprocat at this point. I imagine that's going to help if you want to use Hprocat. But basically you need to make sure that gems have extensions that are in Java as well as C and then they'll work. Also, this is not an officially supported platform by Google, but Google isn't hindering you in any way. Everything you need is part of the Java platform and it's just a matter of you finding a way to work around some of the issues, trying to load as little code as possible for efficiency. And there are some issues, of course, with using data storage a little bit of something new for most people, but hopefully when you get in there and use it, you'll find it's pretty cool. All right. Okay, is this one working? All right. Okay, so before I started working on App Engine, I worked on making Google Web Search faster. So for me, every couple of milliseconds matters. I really don't like the idea that, you know, one out of N requests, however many it is, takes 10 seconds. So I was talking to Woody one day. I was like, wouldn't it be awesome if I could write something that looked like Ruby and it would just spit out this super fast Java code that we could use. And it turns out that's basically what Doobie does. So Doobie looks a lot like Ruby, except that it's statically typed using type inference. It has no runtime other than the Java runtime. And it uses Java's type system instead of Ruby's. Actually, you can configure it to use any type system, but since App Engine has Java, that's what I'm going to talk about. So here's a sample Doobie program. Looks a lot like Ruby. The only difference is right here. You have to declare the types of your function arguments. From that, it infers everything else. It's going to infer the return type. If you had other variables declared within your method, it figures that out for you. So then when you run the Doobie compiler, it's going to create Java for you. This is what it outputs. You don't have to write this, but... You don't have to look at it, actually. If it offends you, you can just ignore it. Right. But, I mean, the thing you can see, there's no... It's not starting up JRuby. It's not doing anything complicated. It's just calling system.out.print line and doing recursive function calls. So here's the more complicated app. This is actually an App Engine app that I wrote as a quick sample. It's meant to look a lot like the Sinatra one you saw before. We've got this super simple datastore adapter here. It's kind of based on Datamapper. So you do the same type of thing. And then, Java serverlets, you get your similar, like, REST sort of API just automatically. So one of the things you'll notice, I'm not declaring any types anywhere here. Well, except for this. But in the serverlet, these are all inferred from the fact that we say we're subclassing HTTP serverlets. There's also these things here. These are plugins which we use for metaprogramming. So I think this is one of the other really awesome things about Doobie is this idea that you're doing metaprogramming at compile time and also adding metaprogramming to Java. Like, there's all these great APIs. Java has, like, Google Web Toolkit, all kinds of data structures and things. But I hate writing actual Java code. So here's as an example of what a plugin looks like. The Doobie compiler is written in Ruby. So, I mean, you don't actually have to understand most of this. But what's going on here, the Doobie compiler, when you run it and it sees this def-edb thing which we've got here, it reads the file name, it goes, opens that file, and calls erb because it's running in Ruby. And so it just has erb, you convert it all to Ruby code and then evaluates that at Doobie at compile time so that when you run it later on, it's just doing string concatenation. So this is what your template looks like. Again, it's using type inference, getting it all from your class, so you don't have to declare any types in your template. So... And I guess it's important to add that you don't... If you have something that works really great in Ruby but it's not especially efficient, it's not an issue because it's a compile time step that your plugin does and then the output is just a Java class. So the step of parsing through your Hamel or erb or whatever is just happening without users involved. So here's the same app actually running in production on Doobie. Same kind of thing. Another thing Doobie can do is output Java source code. Normally it just outputs class files for you. But I added the ability to generate source code so that you can use Google Web Toolkit. Now, I mean, if you went to the talk on JavaScript yesterday, you might have heard people making fun of it, but he was really making fun of Java, not GWT. GWT is an awesome API. It does so much more than just JavaScript. It does do all these tools for making a super fast website, which, like I said, that's what I want. So I've got a quick sample of a really simple Doobie application in GWT. So hello, RubyConf. This is all written in Doobie and the Doobie compiles to Java. It compiles the Java to JavaScript, and so this is just an HTML file. It's all running client-side in the browser. I'm not sure how much you guys have looked at GWT, but GWT compiles, compresses, in an obvious case, the code for each browser, and every browser that connects gets its copy. And if the browser is unknown, it has some generic one that should hopefully work, but it's just not the kind of thing that any person would do by hand. Right. When I first talked to the GWT people, I was like, why would I use GWT? I'm sure I can write better JavaScript than this thing can, but it is an actual compiler. It's doing optimizations for you. Like you said, it generates a different version for each browser. You can set it up to, like, generate a different version for each language or things like that, so it's really awesome. Yeah. How much have you looked at Groovy, though, really? Okay. So the question is, why not Groovy? Well, if the Groovy guys were trying to make something that uses the Groovy syntax, then I would understand that it has a different... I think they're trying to make something that's palatable for Java people. And... I mean, also, I think one of the big things is metaprogramming. I don't know that there's any way to do metaprogramming in Groovy, and I also don't think that Groovy is really statically typed. I think it's got a big runtime that you still have to wait for, and so it still runs much slower than just Java. So at this point, we're just ready for any questions or any other demos, yes? I don't actually have it on this laptop. Yeah. Yes. You mentioned some other libraries from the Groovy side that haven't yet been ported to Java, and you mentioned Hvercott. What ones are key ones that are necessary? Well, so NoCogiri and Hvercott are kind of an interesting example. I love to use Mechanize to do all kinds of scraping and building cookie jars and things like that, and NoCogiri uses some native XML libraries that will not function on App Engine, and there's some work done to fix that. It's not complete yet, and Hvercott had had some issues working with Mechanize, and so now the current version of Mechanize uses NoCogiri. So there's some work there, but it's not insurmountable. It's not that if you really want to make it work and you know a little bit about how to do the Java, then I imagine it could be done. We just need to find someone. Towards the beginning, you talked about pricing and everything, and I noticed that you had 5,000 emails after all the interviews per day, and 50,000 through admin. Who in the world would have 50,000 in one admin account? Can you explain? Because our company sends a lot of emails to our users, of course. We charge for emails basically to keep people from using it for spam, so that's why there's a much lower limit for actual sending to emails other than yourself. You can send as many emails to yourself as you want. So 50,000, it could have been like $1 million. Maybe it's just keeping you from some bug that's going to cripple you having a limit. Yes? The 10-second startup time? Are there cheats that we can use? Well, it's not like there is a 10-second startup time. You can say hello, CGI in 4 seconds or something, but that's not very useful. In between now and when things are sub-second, can we cheat and say respond just immediately That's the whole point is that you can... Actually, can you hold this? I'm going to show you guys an example, I think, of this. I have a app that illustrates this, and I haven't visited it recently or all day today, but let's bring it up. It's called Fiddlesticks. Hopefully I have connectivity. Did I need to hit return? It's going. That seems like that's not right. Well, okay, I think that's kind of hotel data. Okay, so Fiddlesticks is... This main page you see is on a caching server, always available instantly. So assume that the first time you saw this page was the first time we actually connected. So these first two iframes I populated are servlets. One prints some nice HTML, and the other one sends the JSON, and the other one says hello, rack. And I guess you guys are watching, it took about six seconds for rack to actually respond because I haven't been touching the server, it's been sitting idle. But all I have to do here in my config.ru is say some of my URLs go to this servlet or doobie is actually going to be compiled down to a servlet. You don't really have to worry about all those details, but you can write pieces of your app in doobie and they compile the servlets. So yeah, that's another thing I love about GWT. If you use GWT, it's going to compile you a static HTML page for your main page, and then you load the rest with XML, HTTP or RPCs or whatever. You could build your app in Rails 3 and then find well, there's this one piece of my traffic, I can refactor that with doobie, and then it's always a second. And maybe Ruby's getting faster and faster trying to catch that one second, but you can do the doobie today. I'm going to take this question back here. Yeah, we don't have it on this notebook, but maybe you come talk to us afterwards. I had heard that early on that if the app wasn't spooled up, that it would possibly 500. Is that fixed now? Well, you could take the existing code for Java App Engine and just put Rails 2.3 on there yourself and put RubyGems and just put something up there that takes 40 seconds to spin up, but is going to get cut off at 30 seconds and see it not work. So that is absolutely plausible, but you don't want to do that. Can you talk a little bit more about Datastore because I looked at it a while ago and it looked kind of funky, kind of hard to do compared to MySQL or MongoDB or whatever. Right, well, that's it. It's not really comparable to MySQL. Basically, the way I like to think about it is just it's like an array of hashes. Each entity is a hash. You have a string name for all of your properties and then you can store one of, you know, various different types in there and then you can create indexes on those. You can't do things like sums and counters and stuff like that. You can't do joins because, like, the data is on different physical machines. So it's a lot simpler. There are ways to work around it. There are lots of talks online. If you go to, like, the Google IOS side, there's all kinds of videos about how to use the Datastore efficiently. Personally, I would much rather use the Datastore than MySQL. I don't like SQL. I mean, that's one of the reasons, like, I... I think this is my answer. So I have some, you know, code that I've been working on and there are certain things that just work great. Like, you don't have all of the operators. You have, you know, equals to greater than less than and you have a subset of operators. All the extensions work. You can do associations, certain associations, by just using the extensions for the associations and they work as you expect. Which you're going to do has many belongs to many where there's a join table for you. You don't want to do that on App Engine. So what you end up doing is you say, I have a property called My, like, whatever, subscribers and it's a list type and you actually can shove an array of entities in there and search for them and say, give me all the records back that have Bob and then you'll get back a list that Bob is in that array and you can't do that with relational database queries but you can on App Engine so you can bolt your join table kind of into one side or the other and right now you have to do the association stuff by hand but, you know, it's really, it's not that big of a deal. Right. And so, I mean, if somebody wanted to contribute this there are ways that you could efficiently implement joins on App Engine and, you know, somebody could add that to the data map or adapter and it would just be there to you. And that is what we need. We need people to come and say, I built this app and I need this one feature and we can certainly help you or maybe you'll build it and then the next person will add on to that. No, let's take this one. On the same line, what kind of times do you have to content distribution networks where you want to push data out to hundreds or thousands of clients using a web app that's hosted on this server? So, I mean, we don't have a specific caching CDN for you. Like we said, if you put up static files on App Engine they are served from our front ends before it will never even hit your app. So, those will always serve fast. They're served like you're... people are routed to the nearest Google data center and then going over our network to wherever it's actually served from. So, it is going to be faster than just hosting it at some, you know, one single location somewhere. Or some other competitive content distribution network there's nothing blocking you from making the calls that you need to make from there to push your data out. Oh, if you want to do that, no. Yeah. How long those same lines if you have a more efficient way of doing it or a cheaper way of doing it I want to hear about it but I also have to have a feature because without that my app doesn't work. So, I... Yeah, I don't understand exactly what it is you need. Embedded multimedia display units. Right. I update content over the network. I could be on a daily basis cooking on an hourly basis except for these screen stickers. I need to be able to have some kind of controls there. Change those directions, change those things and say, okay, on Monday push this out to these thousand displays so that the ads that come up in the hospital can all say it. Yeah, I mean, depending on how you do it, you can definitely do something like that. You can use URL fetch if you need to have the data stored on S3 or something like that. Right. It's also... It's pushing static content is very easy and it's possible that on S3 you might have a lot more work you have to do to build the app out. In our case, you just push your app code and we handle everything else and it looks like we're out of time. So thank you very much everyone.