IRC Driven Development II

by Michal

In the first part of this article, we described how we use an IRC REPL for SSH tunneling, continuous integration and pinging. Today, we will tell you more about October’s deployment, integration with Github and why is it nearly an AI.

Sometimes I cannot connect to a machine where our October is installed yet I need to restart it. And as always, this puzzling ‘impossible’ task can be easily solved by our IRC REPL itself, as you will see.

Way of the Samurai

First, we have to kill the running bot and we do it with a simple !seppuku command. It orders October to perform a hara-kiri (i.e.exit). However cruel it may be, remember that October has not (yet) passed the Turing test. But it is quite close:

    <michal> hello
    <october> Hello, michal

Anyway, as October ceremonially exits:

   <michal> !seppuku
   *** october (~cinch@81.31.231.91) has quit: Remote host closed the connection
   *** october (~cinch@81.31.231.91) has joined channel #dev

we have to start it again somehow and that can hardly be performed by October itself as it is sleeping with the fishes right now. But we have other tricks in our sleeves. Namely a watchdog which re-spawns the bot whenever it dies so that we can immediately see:

    *** october (~cinch@81.31.231.91) has joined channel #dev

It’s alive!

Self-deploy

Restarting is cool but what for would you use it? Well, apart from the Windows world, where reboot is used mainly as a standard configuration procedure, it is usually needed when new code is deployed. So let’s take it one step further and create !selfupdate command that pulls new code from GIT, install new dependencies (bundle install) and then calls !seppuku all by himself. The watchdog then spawns a new process and October is back online! More fresh than ever!

  <michal> !selfupdate
  <october> pulling changes…
  <october> installing gems…
  <october> done!
  october quit
  october joined

A bit of code

So how does it all work inside? The October re-spawning implementation has 3 parts: an initializer, a loop and a spawner. The initializer is super easy, it just stores env and root folders:

  attr_reader :child, :root, :env

  def initialize(root, env = nil)
    @root = root
    @env = env
  end

The second part, spawner, creates a new process by forking the current one and loads October in it. Any passed block gets executed in the context of a new process so that no code leaks to the watchdog.

  def spawn!
    @child = fork do
      ENV['OCTOBER_ENV'] ||= env

      require File.join(root, "boot")
      require 'october'

      October::Base.start
    end
  end

Last but not least, a loop! method that supervises the spawned processes and creates new ones when they die:

  def loop!
    loop do
      begin
        Process.wait(spawn!)
        warn "process #{child} ended"
      rescue Errno::ECHILD
        warn "process #{child} died or was killed"
      end

      warn "spawning new one in next iteration"

      sleep(1) # throttle spawning in case anything fails
    end
  end

As you can see, forking and process management in Ruby is really easy and straightforward. In case you want to read more about it I cannot but recommend you the Jesse Storimer’s blog. You can also check out the whole spawner code in October repository.

Stop bugging me

As it is annoying to switch to the browser just to do such a common task as creating or reading an issue, we have an October plugin for it. To create an issue just write:

  <someone> !issue create It is broke! | And even with body!

or if you want to ask others about one, all you have to know is its number:

  <jakub> guys, what about #1337 ? Still valid?
  <october> http://github.com/mikz/october/1337 - Play more ping-pong!

Quite an improvement, but that’s not all! On Github, you can attach code to your issues or in other words, every pull request is just an issue with some source code attached. Unfortunately, you cannot convert a normal issue to a pull request via web UI, but you can do it using an API. That allowed us to create yet another command, issue convert:

  <someone> !issue convert 1337 my-branch => master-branch
  <october> Simba, there is a new pull request! https://github.com/3scale/system/pull/1337

You can find more feature in the issues plugin code.

It’s green!

The issues plugin features described above are very simple stuff: they basically allow you to switch one console for another, more accessible to your fingers. But Tiago wrote a plugin that really adds some value by integrating GitHub Issues and Jenkins, a continuous integration server the same way Travis does. Each time a build successfully finishes and informs about it in the #jenkins channel:

<jenkins> Project bcmsectomy build #106: SUCCESS
          https://hudson.3scale.net/job/bcmsectomy/106/

October checks all open pull requests and if one of them belongs to a branch that was just built, it posts a comment informing about it, like this:

Octobot

That way, whenever we are about to merge some code, we can be sure that the tests are green for it.

How do you do?

There are many things October does and many many more that it can do. If you yourself have any suggestions or if you use similar tools to automate your workflow, please share it in the comments!

Published: June 29 2012

  • category:
blog comments powered by Disqus