• Looking for a Job? Let GitHub Help

    pjhyett 24 Nov 2009

    Today we’re rolling out Phase 1 to our GitHub Jobs search engine. Under your Account Settings page, there’s a new tab called Job Profile.

    There you’ll see a simple text area to paste in your resume (or whatever you’d like really), along with a checkbox to confirm you’re available for hire. This is an opt-in program, if you’re not looking for work there’s nothing to do.

    We think the code you’ve put on GitHub is an extremely valuable tool in finding you a great place to work, so now is the time to dust off the code you’re afraid to push and get people excited about it. Also, make sure you’ve filled out your profile information: your name, location, blog/website, and email. All of that information is going to be help you find work.

    Phase 2 of the GitHub Jobs rollout is to expose this information via a private search interface, but we need to know if you’re available for hire first. Please note that none of the data you enter will leave GitHub.

    Step 1 to finding a new job is just a checkbox away!

  • GitHub Talk in NYC

    defunkt 24 Nov 2009

    Do you want to learn about OEmbed? OAuth? Are you dying to hear more about Resque? Is comet still just a buzzword to you? Are the mysteries of BERT-RPC keeping you up at night?

    Well, sir or madam, you are in luck!

    l’ll be talking about GitHub at the Gilt Group’s “Expert Talk” on December 2nd in NYC. Joining me will be leah discussing OEmbed and OAuth.

    Make sure you RSVP if you want to attend. See you there!

  • Optimizing asset bundling and serving with Rails

    kneath 19 Nov 2009

    We spend a lot of time optimizing the front end experience at GitHub. With that said, our asset (css, javascript, images) packaging and serving has evolved to be the best setup I've seen out of any web application I've worked on in my life.

    Originally, I was going to package what we have up into a plugin, but realized that much of our asset packaging is specific our particular app architecture and choice of deployment strategy. If you haven't read up on our deployment recipe read it now. I cannot stress enough how awesome it is to have 14 second no downtime deploys. In any case, you can find the relevant asset bundling code in this gist

    Benefits of our asset bundling

    • Users never have to wait while the server generates bundle caches, ever. With default Rails bundling, each time you deploy, each request until your server generates the bundle has to wait for the bundle to finish. This makes your site pause for about 30s after each deploy.
    • We can use slower asset minifiers (such as YUI or Google Closure) without consequence to our users.
    • Adding new stylesheets or javascripts is as easy as creating the file. No need to worry about including a new file in every layout file.
    • Because we base our ASSET_ID off our git modified date, we can deploy code updates without forcing users to lose their css/js cache.
    • We take full advantage of image caching with SSL while eliminating the unauthenticated mixed content warnings some browsers throw.

    Our asset bundling is comprised of several different pieces:

    1. A particular css & js file structure
    2. Rails helpers to include css & js bundles in production and the corresponding files in development.
    3. A rake task to bundle and minify css & javascript as well as the accompanying changes to deploy.rb to make it happen on deploy
    4. Tweaks to our Rails environment to use smart ASSET_ID and asset servers

    CSS & JS file layout

    Our file layout for CSS & JS is detailed in the README for Javascript, but roughly resembles something like this:

    public/javascripts
    |-- README.md
    |-- admin
    | |-- date.js
    | `-- datePicker.js
    |-- common
    | |-- application.js
    | |-- jquery.facebox.js
    | `-- jquery.relatize_date.js
    |-- dev
    | |-- jquery-1.3.2.js
    | `-- jquery-ui-1.5.3.js
    |-- gist
    | `-- application.js
    |-- github
    | |-- _plugins
    | | |-- jquery.autocomplete.js
    | | `-- jquery.truncate.js
    | |-- application.js
    | |-- blob.js
    | |-- commit.js
    `-- rogue
        |-- farbtastic.js
        |-- iui.js
        `-- s3_upload.js
    

    I like this layout because:

    • It allows me to namespace specific files to specific layouts (gist, github.com, iPhone, admin-only layouts, etc) and share files between apps (common).
    • I can lay out files however I want within each of these namespaces, and reorganize them at will.

    Some might say that relying on including everything is bad practice -- but remember that web-based javascript is almost exclusively onDOMReady or later. That means that there is no dependency order problems. If you run into dependency order issues, you're writing javascript wrong.

    Rails Helpers

    To help with this new bundle strategy, I've created some Rails helpers to replace your standard stylesheet_link_tag and javascript_include_tag. Because of the way we bundle files, it was necessary to use custom helpers. As an added benefit, these helpers are much more robust than the standard Rails helpers.

    Here's the code:

    Our application.html.erb now looks something like this:

    <%= javascript_dev ['jquery-1.3.2', "#{http_protocol}://ajax.googleapis.com/ajax/libs/jquery/1.3.2/jquery.min.js"] %>
    <%= javascript_bundle 'common', 'github' %>
    

    This includes jQuery and all javascript files under public/javascripts/common and public/javascripts/github (recursively). Super simple and we probably won't need to change this for a very long time. We just add files to the relevant directories and they get included magically.

    For pages that have heavy javascript load, you can still use the regular javascript_include_tag to include these files (we keep them under the public/javascripts/rogue directory).

    Bundle rake & deploy tasks

    The javascript_bundle and stylesheet_bundle helpers both assume that in production mode, there'll be a corresponding bundle file. Since we are proactively generating these files, you need to create these manually on each deploy.

    Throw this into lib/tasks/bundle.rake and the corresponding YUI & Closure jars and then run rake bundle:all to generate your javascript. You can customize this to use the minifying package of your choice.

    To make sure this gets run on deploy, you can add this to your deploy.rb:

    Tweaks to production.rb

    The last step in optimizing your asset bundling for deploys is to tweak your production.rb config file to make asset serving a bit smarter. The relevant bits in our file are:

    There's three important things going on here.

    First— If you hit a page using SSL, we serve all assets through SSL. If you're on Safari, we send all CSS & images non-ssl since Safari doesn't have a mixed content warning.

    It is of note that many people suggest serving CSS & images non-ssl to Firefox. This was good practice when Firefox 2.0 was standard, but now that Firefox 3.0 is standard (and obeys cache-control:public as it should) there is no need for this hack. Firefox does have a mixed content warning (albeit not as prominent as IE), so I choose to use SSL.

    Second— We're serving assets out of 4 different servers. This fakes browsers into downloading things faster and is generally good practice.

    Third— We're hitting the git repo on the server (note our deployment setup) and getting a sha of the last changes to the public/stylesheets and public/javascripts directory. We use that sha as the ASSET_ID (the bit that gets tacked on after css/js files as ?sha-here).

    This means that if we deploy a change that only affects app/application.rb we don't interrupt our user's cache of the javascripts and stylesheets.

    Conclusion

    What all of this adds up to is that our deploys have almost no frontend consequence unless they intend to (changing css/js). This is huge for a site that does dozens of deploys a day. All browser caches remain the same and there isn't any downtime while we bundle up assets. It also means we're not afraid to deploy changes that may only affect one line of code and some minor feature.

    All of this is not to say there isn't room for improvement in our stack. I'm still tracking down some SSL bugs, and always trying to cut down on the total CSS, javascript and image load we deliver on every page.

  • Multiple file gist improvements

    kneath 18 Nov 2009

    We've always had the ability to embed multiple file gists:

    But today we added the ability to embed specific files in a multi-file gist!

    We also added permalinks next to each file name so you can hard link to specific files like so

    Enjoy!

  • GitHub Meetup SF: RubyConf Edition

    defunkt 16 Nov 2009

    In SF for RubyConf? Join us this Thursday the 19th at Zeitgeist (map) starting at 9pm!

    Zeitgeist has pitchers and ample outside seating, so bring a jacket. Also: cash only.

    Coming from the conference? Take BART to the 16th st Mission stop then walk North on Valencia (map)

    See you there!

  • GitHub Meetup London

    mojombo 15 Nov 2009

    It’s the last stop on our Europe tour and we’re capping things off with an evening at the Royal George near Soho in London at 19:00 on Monday the 16th. PJ, Scott, and I will be in attendance along with (if the rumors are true) a ton of local developers and tech luminaries from the greater London area. This is a meetup you will not want to miss!


    View Larger Map

  • GitHub Meetup Oslo, Norway

    mojombo 10 Nov 2009

    Continuing our tour of Europe, PJ, and Scott, and I will be in Oslo on Friday the 13th and we’d like to invite you to join us at Gloria Flames at 20:30 for drinks and good times. We’re rolling through Oslo specifically to meet the locals, so don’t disappoint us! I’ll be wearing a “fork you” tshirt so I’ll be easy to identify. See you there!

    If for some reason we need to change venues, check our twitter accounts “mojombo”, “pjhyett”, and “chacon” for updates.


    View Larger Map

  • GitHub Rebase #30

    qrush 10 Nov 2009

    This is the second of many themed Rebases to come…our first was the book edition. In related news, the column has also been going on for over a year now! If you’ve got ideas for projects to feature or themes, don’t be afraid to message me.

    Featured Project

    ooc is a statically typed, object oriented language with some functional programming hints that’s growing up right here on GitHub. The compiler is currently written in Java, and it boils down to C99 so it can run anywhere. Grab the zip from the Downloads section or clone away and set it up. The language has some neat features: everyone’s favorite generic types, a clean import/use system that makes Ruby’s require look like yesterday’s news, and the cover keyword that allows for some really neat abstractions over types and clean interfacing with other C code. If you’re a language geek or need a breath of fresh air, check it out.

    Notably New Projects

    rock is an ooc compiler written in ooc, of course. This has some great examples of quite complex ooc code and aims to replace the Java compiler.

    ooc-sqlite3 is an SQLite driver that’s also just getting off the ground, but it’s starting to pick up some steam. Next stop: a web framework!

    woot is ooc’s first unit testing system, and is headed towards a bright future since it’ll be used to test ooc itself. This dogfood is tasty!

    ooc-glew uses GLEW to open up the power of OpenGL to ooc. There’s also a little Ruby magic baked in to generate the bindings since there’s a lot of functions.

    Stirling3D is also for the graphically minded. This project is a graphics/physics engine that also hooks into OpenGL and is starting to render some neat stuff.

    ooc-yajl is a set of bindings to yajl, a former featured project that is a lightning fast JSON parsing library. It’s also a neat example of how easy it is to hook into C libraries and how the .use files work.

  • Recent UI updates to GitHub

    kneath 8 Nov 2009

    On my first day at GitHub, I asked the crew what they wanted to me to do around here. Their response was something along the lines of "make GitHub sexy" Now that we've been rolling out steady UI updates for about a month, I thought I'd take some time and go over what all I've been working on.

    I previously covered the updated dashboard repository lists and gist improvements, but I haven't had a chance to go over the new userbox, profile pages, account pages, and dashboard headers.

    New userbox

    The new userbox was rolled out to solve a problem we had -- people with long usernames were breaking the UI, forcing links into the next line. I also took the time to reorganize the navigation and spruce up the look & feel.

    New profile pages

    The new profile pages were one of the first purely cosmetic updates to the site. You'll notice a new style of page header being rolled out. This header does have some functional benefits -- but they're subtle. On pages that are yours, you'll notice a slight yellow highlight. This isn't terribly useful right now, but as we roll out new features you'll see why I'm going this route.

    I was also testing out the waters with this page. GitHub has an extremely particular and vocal audience that doesn't represent the typical web user. I wanted to make sure that the general reaction was positive. Judging from the twitter updates and in-person feedback I've gotten, people seem to like the changes -- so you'll see more of this style around the site in the future.

    New Account Settings Pages

    Along with the new profile pages, we also rolled out updated account settings pages. Previously, you had to edit your profile information in-place on the profile page, but now it's grouped with the rest of your settings.

    New billing page

    Previously all of the billing information was crammed into a little grey box in the upper right of the account settings page. With the updated account settings page I decided to create a dedicated billing page. This page shows your plan usage in an easier to access manner and (hopefully) makes it easier to upgrade to paid accounts! :)

    New dashboard headers

    The last update we've rolled out are new-style dashboard headers. The reason for these aren't entirely obvious right now -- but in time they will become a lot more useful. I realize these new headers do push down the repository lists by about 60px, but it was a compromise that I decided to make to give us room for the future.

    Hopefully you guys are enjoying the evolution of the GitHub interface, I've been having a blast watch the feedback pour in after each push.

  • GitHub Meetup Poznań, Poland

    mojombo 7 Nov 2009

    Tom, PJ, and Scott will be hanging out at MOOD Club at 21:30 tonight (Saturday) in Poznań, Poland following the first day of the RuPy Conference. If you’re local or in town for the conference, come by and say hi!

  • New Resque Web UI

    defunkt 4 Nov 2009

    Behold the power of open source! adamcooke has reskinned Resque’s web UI.

    Also now includes live updating:

    Thanks Adam!

  • Introducing Resque

    defunkt 3 Nov 2009

    Resque is our Redis-backed library for creating background jobs, placing those jobs on multiple queues, and processing them later.

    Background jobs can be any Ruby class or module that responds to perform. Your existing classes can easily be converted to background jobs or you can create new classes specifically to do work. Or, you can do both.

    All the details are in the README. We've used it to process over 10m jobs since our move to Rackspace and are extremely happy with it.

    But why another background library?

    A Brief History of Background Jobs

    We've used many different background job systems at GitHub. SQS, Starling, ActiveMessaging, BackgroundJob, DelayedJob, and beanstalkd. Each change was out of necessity: we were running into a limitation of the current system and needed to either fix it or move to something designed with that limitation in mind.

    With SQS, the limitation was latency. We were a young site and heard stories on Amazon forums of multiple minute lag times between push and pop. That is, once you put something on a queue you wouldn't be able to get it back for what could be a while. That scared us so we moved.

    ActiveMessaging was next, but only briefly. We wanted something focused more on Ruby itself and less on libraries. That is, our jobs should be Ruby classes or objects, whatever makes sense for our app, and not subclasses of some framework's design.

    BackgroundJob (bj) was a perfect compromise: you could process Ruby jobs or Rails jobs in the background. How you structured the jobs was largely up to you. It even included priority levels, which would let us make "repo create" and "fork" jobs run faster than the "warm some caches" jobs.

    However, bj loaded the entire Rails environment for each job. Loading Rails is no small feat: it is CPU-expensive and takes a few seconds. So for a job that may take less than a second, you could have 8 - 20s of added overhead depending on how big your app is, how many dependencies it requires, and how bogged down your CPU is at that time.

    DelayedJob (dj) fixed this problem: it is similar to bj, with a database-backed queue and priorities, but its workers are persistent. They only load Rails when started, then process jobs in a loop.

    Jobs are just YAML-marshalled Ruby objects. With some magic you can turn any method call into a job to be processed later.

    Perfect. DJ lacked a few features we needed but we added them and contributed the changes back.

    We used DJ very successfully for a few months before running into some issues. First: backed up queues. DJ works great with small datasets, but once your site starts overloading and the queue backs up (to, say, 30,000 pending jobs) its queries become expensive. Creating jobs can take 2s+ and acquiring locks on jobs can take 2s+, as well. This means an added 2s per job created for each page load. On a page that fires off two jobs, you're at a baseline of 4s before doing anything else.

    If your queue is backed up because your site is overloaded, this added overhead just makes the problem worse.

    Solution: move to beanstalkd. beanstalkd is great because it's fast, supports multiple queues, supports priorities, and speaks YAML natively. A huge queue has constant time push and pop operations, unlike a database-backed queue.

    beanstalkd also has experimental persistence - we need persistence.

    However, we quickly missed DJ features: seeing failed jobs, seeing pending jobs (beanstalkd only allows you to 'peek' ahead at the next pending job), manipulating the queue (e.g. running through and removing all jobs that were created by a bug or with a bad job name), etc. A database-queue gives you a lot of cool features. So we moved back to DJ - the tradeoff was worth it.

    Second: if a worker gets stuck, or is processing a job that will take hours, DJ has facilities to release a lock and retry that job when another worker is looking for work. But that stuck worker, even though his work has been released, is still processing a job that you most likely want to abort or fail.

    You want that worker to fail or restart. We added code so that, instead of simply retrying a job that failed due to timeout, other workers will a) fail that job permanently then b) restart the locked worker.

    In a sense, all the workers were babysitting each other.

    But what happens when all the workers are processing stuck or long jobs? Your queue quickly backs up.

    What you really need is a manager: someone like monit or god who can watch workers and kill stale ones.

    Also, your workers will probably grow in memory a lot during the course of their life. So you need to either make sure you never create too many objects or "leak" memory, or you need to kill them when they get too large (just like you do with your frontend web instances).

    At this point we have workers processing jobs with god watching them and killing any that are a) bloated or b) stale.

    But how do we know all this is going on? How do we know what's sitting on the queue? As I mentioned earlier, we had a web interface which would show us pending items and try to infer how many workers are working. But that's not easy - how do you have a worker you just kill -9'd gracefully manage its own state? We added a process to inspect workers and add their info to memcached, which our web frontend would then read from.

    But who monitors that process. And do we have one running on each server? This is quickly becoming very complicated.

    Also we have another problem: startup time. There's a multi-second startup cost when loading a Rails environment, not to mention the added CPU time. With lots of workers doing lots of jobs being restarted on a non-trival basis, that adds up.

    It boils down to this: GitHub is a warzone. We are constantly overloaded and rely very, very heavily on our queue. If it's backed up, we need to know why. We need to know if we can fix it. We need workers to not get stuck and we need to know when they are stuck.

    We need to see what the queue is doing. We need to see what jobs have failed. We need stats: how long are workers living, how many jobs are they processing, how many jobs have been processed total, how many errors have there been, are errors being repeated, did a deploy introduce a new one?

    We need a background job system as serious as our web framework. I highly recommend DelayedJob to anyone whose site is not 50% background work.

    But GitHub is 50% background work.

    In Search of a Solution

    In the Old Architecture, GitHub had one slice dedicated to processing background jobs. We ran 25 DJ workers on it and all they did was run jobs. It was known as our "utility" slice.

    In the New Architecture, certain jobs needed to be run on certain machines. With our emphasis on sharding data and high availability, a single utility slice no longer fit the bill.

    Both beanstalkd and bj supported named queues or "tags," but DelayedJob did not. Basically we needed a way to say "this job has a tag of X" and then, when starting workers, tell them to only be interested in jobs with a tag of X.

    For example, our "archive" background job creates tarballs and zip files for download. It needs to be run on the machine which serves tarballs and zip files. We'd tag the archive job with "file-serve" and only run it on the file serving slice. We could then re-use this tag with other jobs that needed to only be run on the file serving slice.

    We added this feature to DelayedJob but then realized it was an opportunity to re-evaluate our background job situation. Did someone else support this already? Was there a system which met our upcoming needs (distributed worker management - god/monit for workers on multiple machines along with visibility into the state)? Should we continue adding features to DelayedJob? Our fork had deviated from master and the merge (plus subsequent testing) was not going to be fun.

    We made a list of all the things we needed on paper and started re-evaluating a lot of the existing solutions. Kestrel, AMQP, beanstalkd (persistence still hadn't been rolled into an official release a year after being pushed to master).

    Here's that list:

    • Persistence
    • See what's pending
    • Modify pending jobs in-place
    • Tags
    • Priorities
    • Fast pushing and popping
    • See what workers are doing
    • See what workers have done
    • See failed jobs
    • Kill fat workers
    • Kill stale workers
    • Kill workers that are running too long
    • Keep Rails loaded / persistent workers
    • Distributed workers (run them on multiple machines)
    • Workers can watch multiple (or all) tags
    • Don't retry failed jobs
    • Don't "release" failed jobs

    Redis to the Rescue

    Can you name a system with all of these features:

    • Atomic, O(1) list push and pop
    • Ability to paginate over lists without mutating them
    • Queryable keyspace, high visibility
    • Fast
    • Easy to install - no dependencies
    • Reliable Ruby client library
    • Store arbitrary strings
    • Support for integer counters
    • Persistent
    • Master-slave replication
    • Network aware

    I can. Redis.

    If we let Redis handle the hard queue problems, we can focus on the hard worker problems: visibility, reliability, and stats.

    And that's Resque.

    With a web interface for monitoring workers, a parent / child forking model for responsiveness, swappable failure backends (so we can send exceptions to, say, Hoptoad), and the power of Redis, we've found Resque to be a perfect fit for our architecture and needs.

    web ui

    We hope you enjoy it. We certainly do!

  • Commons Based Peer Production

    defunkt 2 Nov 2009

    ab5tract has a great post looking at GitHub “through the lens of the ethics of commons-based peer production.”

    A key quote which puts it in perspective for me is this:

    The software further induces virtue in its participants through the `git blame` function, which immediately calls up the person responsible for a commit. In practice it used as much to know who to praise as it is to know who to berate, but it fulfills one of the the paper’s common criteria for extant commons-based peer production: that of a mechanism to mitigate the potential impacts of malicious users. Slashdot has its moderation system, Wikipedia its editors, and git has `blame`. In fact this functionality is a crucial part of what enables the ‘virtue spreading virtue’ element of such peer production.

    Read the blog post for the whole scope. Thanks ab5tract!

  • GitHub Meetup SF #9

    Its time for a meetup! This week we’ll be going to a faraway place, a place once thought to only exist in legend, a land they call the ‘Richmond’. According to local lore there’s a bar called Buckshot where you can play skee ball and shuffleboard while you shoot the breeze. And even if you dont actually spot any mythical beasts, you might get a chance to talk to Chris about unicorns. 8pm Thursday November 5th.

  • Load Balancing at GitHub

    mojombo 2 Nov 2009

    We’ve had a number of inquiries into why we chose ldirectord as our primary load balancer for the new GitHub architecture. As I’ve mentioned before (and more on this later), we’ve hired the excellent team at Anchor as our server specialists. Our team lead over there is Matt Palmer, and we left the choice of load balancer up to him and his expertise. He’s taken it upon himself to explain the driving factors behind his choice, and it makes for an enlightening read if you’re interested in such things. Just head on over to the Anchor blog to check it out:

    http://www.anchor.com.au/blog/2009/10/load-balancing-at-github-why-ldirectord/

    Be sure to read the comments where the author of haproxy weighs in on the post and adds some additional perspective. Like most technology decisions, there is no single correct answer. Only tradeoffs and preferences.