Permalink
Browse files

http_resque 0.1

  • Loading branch information...
0 parents commit fc740594538552337cf78cf0708ef601c5a298dd @philc committed Mar 20, 2012
Showing with 124 additions and 0 deletions.
  1. +4 −0 .gitignore
  2. +4 −0 Gemfile
  3. +3 −0 README.markdown
  4. +1 −0 Rakefile
  5. +83 −0 bin/http_resque
  6. +25 −0 http_resque.gemspec
  7. +1 −0 lib/http_resque.rb
  8. +3 −0 lib/http_resque/version.rb
@@ -0,0 +1,4 @@
+*.gem
+.bundle
+Gemfile.lock
+pkg/*
@@ -0,0 +1,4 @@
+source "http://rubygems.org"
+
+# Specify your gem's dependencies in http_resque.gemspec
+gemspec
@@ -0,0 +1,3 @@
+HTTP Resque
+===========
+Docs forthcoming.
@@ -0,0 +1 @@
+require "bundler/gem_tasks"
@@ -0,0 +1,83 @@
+#!/usr/bin/env ruby
+
+# This wraps the Resque process with a thin HTTP API which enables you to manipulate jobs using HTTP requests
+# and run jobs synchronously, off-box, for the purposes of integration testing background jobs. This is
+# necessary because background jobs fail notoriously often in production and so they need integration -- not
+# unit -- tests. This helps you to cleanly write those integration tests.
+#
+# Usage:
+# QUEUE=* http_resque -p 8080
+# The server uses port 4567 by default. Use -p to specify an alternate port.
+# You'll note that the QUEUE environment variable is used just like it is when running `rake resque:work`.
+
+# Once it's started, you can access these URLs to manipulate jobs:
+# GET /queues/:queue/jobs
+# DELETE /queues/:queue/jobs
+# POST /queues/:queue/jobs
+# GET /queues/:queue/result_of_oldest_job
+
+require "sinatra/base"
+require "thin"
+require "resque"
+require "rake"
+require "json"
+
+# Load the Rakefile which should in turn require all of their Resque job classes.
+# TODO(philc): The path to this Rakefile should be an argument.
+load "./Rakefile"
+
+class HttpResque < Sinatra::Base
+ settings.server = "thin"
+
+ STDOUT.sync = STDERR.sync = true
+
+ # Run rake resque:work in a background process. It will exit when this process exits.
+ fork { Rake::Task["resque:work"].invoke }
+
+ settings.port = ARGV.include?("-p") ? ARGV[ARGV.index("-p") + 1] : ENV["PORT"]
+
+ get "/" do
+ "http_resque is here."
+ end
+
+ # The Resque representation of up to 25 jobs in this queue, *oldest* first. Resque jobs look like this:
+ # { "class"=>"DeployBuild", "args"=>["my_embed_code", "my_youtube_synd_id"] }
+ get "/queues/:queue/jobs" do
+ (Resque.peek(params[:queue], 0, 25) || []).to_json
+ end
+
+ delete "/queues/:queue/jobs" do
+ Resque.remove_queue(params[:queue])
+ nil
+ end
+
+ # Create a new job.
+ # - queue: the queue to enqueue this job into.
+ # - arguments: optional; an array of arguments for the Resque job.
+ post "/queues/:queue/jobs" do
+ halt(400, "Provide a valid JSON body.") unless json_body
+ klass = json_body["class"]
+ halt(400, "Specify a class.") unless klass
+ klass = Object.const_get(klass)
+ Resque.enqueue_to(params[:queue], klass, *json_body["arguments"])
+ nil
+ end
+
+ # Executes the job at the head of this queue (the oldest job), and blocks until it's finished.
+ # This is useful for scripting integration tests which verify that a background job is working correctly.
+ get "/queues/:queue/result_of_oldest_job" do
+ job = Resque::Job.reserve(params[:queue])
+ halt(404, "No jobs left in #{params[:queue]}") unless job
+ begin
+ job.perform
+ rescue => error
+ halt(500, "This job raised an exception when run: " +
+ "#{job.inspect}\n#{error.class}: #{error.message}\n#{error.backtrace.join("\n")}")
+ end
+ nil
+ end
+
+ def json_body() @json_body ||= JSON.parse(request.body.read) rescue nil end
+
+ run! if app_file == $0
+end
@@ -0,0 +1,25 @@
+# -*- encoding: utf-8 -*-
+$:.push File.expand_path("../lib", __FILE__)
+require "http_resque/version"
+
+Gem::Specification.new do |s|
+ s.name = "http_resque"
+ s.version = HttpResque::VERSION
+ s.authors = ["Phil Crosby"]
+ s.email = ["phil.crosby@gmail.com"]
+ s.homepage = "http://github.com/philc/http_resque"
+ s.summary = "A small HTTP wrapper around Resque, so you can schedule and test jobs over HTTP."
+
+ s.rubyforge_project = "http_resque"
+
+ s.files = `git ls-files`.split("\n")
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
+ s.require_paths = ["lib"]
+
+ s.add_runtime_dependency "thin"
+ s.add_runtime_dependency "resque"
+ s.add_runtime_dependency "rake"
+ s.add_runtime_dependency "json"
+ s.add_runtime_dependency "sinatra"
+end
@@ -0,0 +1 @@
+require "howdy/version"
@@ -0,0 +1,3 @@
+module HttpResque
+ VERSION = "0.0.1"
+end

0 comments on commit fc74059

Please sign in to comment.