Capistrano and Bundler

Sounds great doesn't it? Carefree deployments and gem management for your app. However, I ran into a few pitfalls that made the first experience less than carefree.

bundle:install step

After integrating bundler into capistrano with

require 'bundler/capistrano'

a bundle:install step gets kicked off to install your gems locally.  Pretty cool, but beware of defaults if you're on a multiserver deployment setup.  The default step flags are --deployment --quiet which will download all of the gems from the net.  Maybe not so bad for some folks but on a beefy rails app, this took forever across four servers and 38 gems.  Nevertheless, capistrano is easily customizable and can make this easier with the following line:

set :bundle_flags, "--deployment --quiet --local"

In order for this to work properly though, make sure and package up the gems with your application!

Custom rake tasks

The app I work on has a few custom steps for compiling a custom Ruby library, building extra documentation, etc. so there are a few more after "deploy:update_code" steps to address upon deployment.  Everything was pretty simple and easy to update for bundler; the only trick is knowing you have to do this update.

Each custom step was built into a rake task for lazyness in development, so each resembled something like this:

namespace :xapian do
   desc "Rebuild Xapian index."
   task :rebuild, :roles => :xapian_index do
     run "cd #{release_path}; rake xapian:rebuild_index models=\"MyModelName\"", :env => {'RAILS_ENV' => stage}
   end
end

We were calling rake directly, but this will lead you to step failures pretty quickly if the version of rake differs (or doesn't exist) in the deployment environment.  Simply replace rake with #{rake}.  The step will automatically be executed as #{bundle_cmd} rake instead (e.g. bundle exec rake by default).

 

Filed under  //  bundler   capistrano   deployment   rails   ruby  
Posted

Versioning ActionWebService on Rails

I started a Rails project a few years ago that has grown up.  These days, there is a main consumer of a SOAP API provided through ActionWebService (with more on the way).  Most generally try and head down the RESTful path, but with server-to-server communication, it just made it easier to take a structured path.  (Custom XML/JSON output, yuck.)

Since the client system is actually the server for a desktop client, it became more necessary to independently update the two servers.  This did pose a bit of a problem with SOAP API bindings in .NET.  We wanted to establish a backwards compatible base API (to maintain the status quo) and also start working on a few API breaking updates.  This would normally be pretty easy in rails with namespaces but it unfortunately doesn't work out so well for ActionWebService.

ActionWebService actually supports a few different models of dispatching actions: direct, delegated, and layered.  Direct just maps a controller's actions to the entire described API.  Delegated enables exposing single methods as SOAP actions from another controller.  Lastly, layered is a lot like direct and delegated mixed; separate ports are created for each layered implementation, and everything is described in the same wsdl.

So...everything should be great, right? Well, it turned out that all of the session code broke.  Since the 'versioned' implementations were actually instantiated from the original controller, they're not provided the same environment as the top level. This little trick from the ruby-forum re-instated the functionality (with a minor edit):

class ServicesController < ApplicationController
    web_service_dispatching_mode :layered
    web_service(:v1) { ServicesV1Controller.new(self) }
  end

 

class ServicesV1Controller < ApplicationController
    def initialize(self)
      @controller = self
      @session = @controller.session
    end
  end

We're still working through some of the kinks in making the API fully backwards compatible, but this got us a long ways to supporting multiple API versions with SOAP.

 

Helpful post on API versioning: http://stackoverflow.com/questions/389169/best-practices-for-api-versioning

Filed under  //  actionwebservice   rails   ruby   soap   versioning   webdev  
Posted

Appcelerator: Titanium

I've been intrigued by Titanium's cross-platform support and use of HTML/CSS to code up cool apps instead of in Adobe AIR.  However, I've been curious if I could avoid using Appcelerator's cloud building services for work projects.  Trying this forum post out: http://developer.appcelerator.com/question/73271/how-to-package-your-desktop-app-yourself-ie-not-use-the-cloud  Hopefully it works...

Posted

Photoshop with large files

My wife and I had been hunting down a wedding photo of my parents and finally got one yesterday (thanks Grandma!).  I quickly scanned it at her house at 2400dpi into TIFF to make sure I had everything possible for correcting it and enlarging the 5x5" print to 11x24".  Luckily, I had my laptop to transfer the 300MB file.

As one would expect, the photo is riddled with color decay, red spots across a large section, and dust and scratches all over it.  I've been editing all morning with nine layers adjusting colors and such.  Suddenly, Photoshop gives me a warning about being unable to save past the 2GB boundary.  Never fear though, switch to Adobe's "Large Document Format" (aka PSB) and keep working.  Unfortunately, PDB is likely to be less compatible with non-Adobe products though.

Hope this helps...

Posted

Family Computer Help Request

How's the fam. How's the Job. Hope all is well. Blah Blah Blah. I have a computer problem.

Posted

Wicked fast mallocs (tcmalloc)

"TCMalloc is faster than the glibc 2.3 malloc (available as a separate library called ptmalloc2) and other mallocs that I have tested. ptmalloc2 takes approximately 300 nanoseconds to execute a malloc/free pair on a 2.8 GHz P4 (for small objects). The TCMalloc implementation takes approximately 50 nanoseconds for the same operation pair. Speed is important for a malloc implementation because if malloc is not fast enough, application writers are inclined to write their own custom free lists on top of malloc. This can lead to extra complexity, and more memory usage unless the application writer is very careful to appropriately size the free lists and scavenge idle objects out of the free list"

http://goog-perftools.sourceforge.net/doc/tcmalloc.html

Posted

Hello (Posterious) World

Giving posterious a whirl, so..... hello world. :)

Posted