You’re going to need to take control of your own deployment. Heroku, for instance, isn’t going to handle that well.
But first, here’s a little parable about Bob (who is, um, totally not an alias for my early mistakes… Probably.)
The Parable About Bob
Bob was an old-time C programmer. When he built C programs in his spare time, nobody ever saw them. You can give people source code, but usually they can’t use it in that world. And building an installer is horrible, especially if you have any friends with a different OS than you use. That used to happen, back in the day.
Ruby on Rails was awesome and Bob loved it. You could put something on a server and then your friends could use it. How cool is that?
And it had some fun new features like server-sent events. If you can make a good chat server, chances are good you can make a game, too. Bob was trying that out.
And actually, he came up with a kind of cool game. There were some hexes and some things in them. Stuff moved around a little and there was a chat window next to it.
Bob was running everything on his development machine, which was a little complicated, but he could manage.
Bob had a server that he used for a few things, and mostly he just installed stuff by hand.
So he went ahead and ran everything he needed (back then: Redis, an even older version of Juggernaut and his Rails app.) And everything was fine.
Of course, he had to set everything up again when he rebooted. But that wasn’t a big deal.
Also, his app would crash sometimes. That wasn’t a huge thing.
Juggernaut would also crash sometimes, and that meant restarting it and his Rails app.
And every time somebody logged in, something wasn’t working. Sometimes they emailed Bob. Mostly, they just didn’t look at the game, even though it was kinda cool.
Before long, Bob didn’t feel like showing off his game to his friends any more.
In fact, he was kinda done building games. Suddenly, Ruby on Rails kind of sucked.
Maybe Don’t Be Bob?
Bob didn’t know it, but a lot of his problem was that deploying Rails apps suddenly gets hard when you care about the details. Anything you’d build an interactive game or a chat server on turns out to require some work. You need to care about what app server you use (Unicorn? Thin?) You need to care about running custom servers (Redis? Something with EventMachine?)
Unfortunately, that’s harder than it should be. Right now, off-the-rack solutions don’t usually work.
Right now, you need to use a big custom stack of tools, and they’re hard to use.
Or you could let me do it.
Sadly, I know all about Bob. And it sucks to be him.
Instead, let me show you how to set up your deploy the right way — that means easy to modify, easy to re-roll-out, easy to run custom stuff.
My pilot program is open right now.
When I create and promote fun content, I get more subscribers, more goodwill and more engagement.
When I ask my audience to buy things, or even sit through being asked to buy things, I lose those things, by and large.
So this product trek is kind of an alternation — "power up" my audience by giving good things, and then turn that into "hey guys, buy my class" or "please fill out this survey" or whatever I’m asking of them.
Unrelatedly: I don’t feel like a person who sells products when I have successes. I feel like a person who sells products when I’m mid-slog and I know exactly what part comes next.
Deployment comes with far too many tools. For instance, this whole set is often used together:
And that’s not counting the smaller things like Vagrant plugins, Capistrano plugins, the many Chef cookbooks and so on, which would also be used with these. And it’s definitely not counting the many, many competitors. That whole list is just one stack of tools.
For some of them, it’s clear why you use them. VirtualBox? Yeah, okay, something has to make a VM if you test locally.
But why do you need both an “app deploy” tool (Capistrano) and a “server configuration” tool (Chef)? Can’t your server configuration just include your app? For that matter, if your “app deploy” tool runs scripts as root, can’t it configure your server?
There Can Be Only One?
Some people do use just one. It’s possible to deploy apps through Chef, but please don’t! It’s possible to do all your server configuration through Capistrano — really, really don’t.
For best results, think of Chef and Capistrano as two separate tools for two different jobs.
So what are those jobs?
Some famous people told me how to get superpowers. I did. They all happen to agree on this topic. Now I’m going to tell you the same secret. I’ll even help you out a bit more.
The most powerful, important thing you can do is to get your code in front of the people who will use it. Do it as fast as possible. Do it when it’s not ready yet. Do it when it makes you uncomfortable.
What does that have to do with superpowers, though? We’ll get there. But first, more about shipping code.
But It’s Not Ready!
In the end, it boils down to this. You’re somebody who is reading about software when you don’t have to. Right here in this post, even! You care about your craft.
First off, let’s just say: Heroku is awesome. There are all kinds of great reasons to use it, and I would never, never claim that Heroku is wrong for all deployments.
But it’s also not right for all deployments. Let’s talk about when it’s wrong and when it’s right.
Heroku’s big advantages are:
- really easy to deploy
- really easy to scale
- mostly everything just works
Those are big advantages. Sometimes they’re the most important thing for your project. When they are, you should absolutely use Heroku.
But why might you not?
First, the elephant in the room: the cost. Heroku gives you limited free hours per month, and after that it’s expensive. Background threads or processes also cost extra.
A single minimum-power dyno runs you $36 per month, assuming you need barely any space in Postgres. Heroku is basically going to cost you at least twice what a VPS would cost (e.g. Linode or Digital Ocean) and give you much less power. If you process many simultaneous requests or run many background threads, it will be at least three or four times as expensive for the same power.
Here’s a video about threads in Ruby – how do you code them? What are the problems with them? I’m planning a few more short videos about Ruby concurrency. I don’t think enough people have a good grasp of the tradeoffs and problems of running more than one chunk of code at once, in Ruby or in general.
I’m also still learning Camtasia and the rest of the video toolchain. So I hope I’ll look back in a few months and think, “wow, this looks really bad now!”
In the mean time, enjoy! Here’s a transcript:
Ruby supports threads, of course. Modern Ruby, anything 1.9 and higher, uses the normal kind of threads for your operating system, or JVM threads if you’re using JRuby. [next slide] Here’s the code to make that happen. The code inside the Thread.new block runs in the thread, while your main program skips the block and runs the join. “Join” means to wait for the thread to finish - in this case, it waits up to 30 seconds since that’s what we told it. With no argument, join will wait forever. You’ll probably want a begin/rescue/end inside your thread to print a message if an uncaught exception happens. By default, Ruby just lets the thread die silently. Or you can set an option to have Ruby kill your whole program, but I prefer to print a message. In “normal” Ruby, Matz’s Ruby, there’s a Global Interpreter Lock. Two threads can’t run Ruby code at the same time in the same process. So most Ruby threads are waiting for something to complete, like an HTTP request or a database query. [next slide] What are Ruby threads good for if there’s a global lock? In Matz’s Ruby, you’ll mostly want to use them for occasional events. RabbitMQ messages, timeouts, and Cron-style timed jobs are all good. Since you can only have one thread doing real work in Ruby at once, threads are best when your process is mostly idle. JRuby and Rubinius users can chuckle here. Their Ruby handles multiple Ruby threads working at the same time without a hiccup. So what problems do you sometimes see with Ruby threads? [next slide] With the Global Interpreter Lock, threads can switch back and forth between CPUs, sometimes very often. If you see Ruby threads performing horribly in production with Matz’s Ruby or using way too much CPU, try locking the thread down to a single CPU. Your operating system has commands for that — Google them. Next, if the main thread dies or finishes, your program ends. That’s a feature, but sometimes it’s surprising. To have your main thread of execution stick around, use join on the other threads to let them finish. And of course an unhandled exception in a child thread kills only the child thread, and it does it completely silently. Use a begin/rescue/end to print errors to console or set the Ruby option to kill the main program when a child thread dies from an unhandled exception.