hirefire-resource 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,4 @@
1
+ .DS_Store
2
+ *.swp
3
+ *.swo
4
+ *.gem
data/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # [HireFire](http://hirefireapp.com/) - The Heroku Dyno Manager
2
+
3
+ *Note: This gem currently only applies to users that are using the new HireFire beta program.
4
+ Once out of beta, this will become the default gem for new users.*
5
+
6
+ HireFire is a hosted service that manages / autoscales your [Heroku](http://heroku.com/) dynos.
7
+
8
+ It supports the following stacks:
9
+
10
+ * Celadon Cedar
11
+ * Badious Bamboo
12
+ * Argent Aspen
13
+
14
+ It supports practically any worker library. We provide out-of-the-box support for:
15
+
16
+ * Delayed Job
17
+ * Resque
18
+ * Qu
19
+ * QueueClassic
20
+
21
+ *Note that you can write your own worker queue logic for almost any other worker library as well.
22
+ HireFire can scale multiple individual worker libraries at the same time, as well as multiple individual queues for any worker library.*
23
+
24
+ It supports practically any Rack-based application or framework, such as:
25
+
26
+ * Ruby on Rails
27
+ * Sinatra
28
+ * Padrino
29
+ * Bare Rack Apps
30
+
31
+ We provide convenient macros for the above mentioned worker libraries to calculate the queue size for each of them.
32
+ If you wish to conribute more macros for other existing worker libraries feel free to send us a pull request.
33
+
34
+ Here is an example with Ruby on Rails 3. First, add the gem to your `Gemfile`:
35
+
36
+ ```ruby
37
+ gem "hirefire-resource"
38
+ ```
39
+
40
+ Then, all you have to do is create an initializer in `config/initializers/hirefire.rb` and add the following:
41
+
42
+ ```ruby
43
+ HireFire::Resource.configure do |config|
44
+ config.dyno(:resque_worker) do
45
+ HireFire::Macro::Resque.queue
46
+ end
47
+
48
+ config.dyno(:dj_worker) do
49
+ HireFire::Macro::Delayed::Job.queue
50
+ end
51
+ end
52
+ ```
53
+
54
+ This will allow HireFire to read out the queues for both Resque and Delayed Job. By default these macros will count all the queues combined if you are using multiple
55
+ different queues for each worker library. You can also pass in specific queues to count, like so:
56
+
57
+ ```ruby
58
+ HireFire::Resource.configure do |config|
59
+ config.dyno(:resque_worker) do
60
+ HireFire::Macro::Resque.queue(:mail, :backup)
61
+ end
62
+
63
+ config.dyno(:dj_worker) do
64
+ HireFire::Macro::Delayed::Job.queue(:encode, :compress)
65
+ end
66
+ end
67
+ ```
68
+
69
+ This will tell HireFire to count the total amount of jobs from the `mail` and `backup` queue for the `resque_worker` dyno, and the `encode` and `compress` queues for the `dj_worker` dyno.
70
+ The `resque_worker` refers to the `resque_worker` in your `Procfile`, and the `dj_worker` refers to the `dj_worker` in the `Procfile`. In this case the `Procfile` would look something like this:
71
+
72
+ ```
73
+ resque_worker: QUEUE=mail,backup bundle exec rake resque:work
74
+ dj_worker: QUEUES=encode,compress bundle exec rake jobs:work
75
+ ```
76
+
77
+ Now that HireFire will scale both of the these dyno types based on their individual queue sizes. To customize how they scale, log in to the HireFire web interface.
78
+
79
+ Visit the [official website](http://hirefireapp.com/) for more information!
80
+
data/bin/hirefire ADDED
@@ -0,0 +1,4 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require File.expand_path("../../lib/hirefire/cli", __FILE__)
4
+
data/bin/hirefireapp ADDED
@@ -0,0 +1,5 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ puts "Please use the `hirefire` utility instead of the `hirefireapp` utility."
4
+ exit 1
5
+
@@ -0,0 +1,17 @@
1
+ # encoding: utf-8
2
+
3
+ Gem::Specification.new do |gem|
4
+ gem.name = "hirefire-resource"
5
+ gem.version = "0.0.1"
6
+ gem.platform = Gem::Platform::RUBY
7
+ gem.authors = "Michael van Rooijen"
8
+ gem.email = "michael@hirefireapp.com"
9
+ gem.homepage = "http://hirefireapp.com/"
10
+ gem.summary = "HireFire - The Heroku Dyno Manager"
11
+ gem.description = "HireFire - The Heroku Dyno Manager"
12
+
13
+ gem.files = %x[git ls-files].split("\n")
14
+ gem.executables = ["hirefire", "hirefireapp"]
15
+ gem.require_path = "lib"
16
+ end
17
+
@@ -0,0 +1,14 @@
1
+ # encoding: utf-8
2
+
3
+ HIREFIRE_PATH = File.expand_path("../hirefire", __FILE__)
4
+
5
+ %w[middleware resource].each do |file|
6
+ require "#{HIREFIRE_PATH}/#{file}"
7
+ end
8
+
9
+ %w[delayed_job resque qu qc].each do |file|
10
+ require "#{HIREFIRE_PATH}/macro/#{file}"
11
+ end
12
+
13
+ require "#{HIREFIRE_PATH}/railtie" if defined?(Rails::Railtie)
14
+
@@ -0,0 +1,48 @@
1
+ # encoding: utf-8
2
+
3
+ require "open-uri"
4
+ require "openssl"
5
+
6
+ OpenSSL::SSL.send(:remove_const, :VERIFY_PEER)
7
+ OpenSSL::SSL::VERIFY_PEER = OpenSSL::SSL::VERIFY_NONE
8
+
9
+ def usage
10
+ puts(<<-EOS)
11
+
12
+ Usage:
13
+
14
+ hirefire http://mydomain.com/
15
+
16
+ Or locally:
17
+
18
+ gem install thin
19
+ [bundle exec] thin start -p 3000
20
+ hirefire http://127.0.0.1:3000/
21
+
22
+ SSL Enabled URLs:
23
+
24
+ hirefire https://mydomain.com/
25
+
26
+ EOS
27
+ end
28
+
29
+ if (url = ARGV[0]).nil?
30
+ usage
31
+ else
32
+ begin
33
+ response = open(File.join(url, "hirefire", "test")).read
34
+ rescue
35
+ puts
36
+ puts "Error: Could not connect to: #{url}"
37
+ usage
38
+ exit 1
39
+ end
40
+
41
+ if response =~ /HireFire/
42
+ puts response
43
+ else
44
+ puts "Error: Could not find HireFire at #{url}."
45
+ exit 1
46
+ end
47
+ end
48
+
@@ -0,0 +1,44 @@
1
+ # encoding: utf-8
2
+
3
+ module HireFire
4
+ module Macro
5
+ module Delayed
6
+ module Job
7
+ extend self
8
+
9
+ # Determines whether `ActiveRecord (3)` or `Mongoid` is being used.
10
+ # Once determined, it will build the appropriate query criteria in order
11
+ # to count the amount of jobs in a given queue and return the result.
12
+ #
13
+ # Example:
14
+ #
15
+ # HireFire::Macro::Delayed::Job.queue # all queues
16
+ # HireFire::Macro::Delayed::Job.queue("email") # only email queue
17
+ # HireFire::Macro::Delayed::Job.queue("audio", "video") # audio and video queues
18
+ #
19
+ # @param [Array] queues provide one or more queue names, or none for "all".
20
+ # @return [Integer] the number of jobs in the queue(s).
21
+ def queue(*queues)
22
+ queues.flatten!
23
+
24
+ if defined?(ActiveRecord)
25
+ c = ::Delayed::Job
26
+ c = c.where(:failed_at => nil)
27
+ c = c.where("run_at <= ?", Time.now.utc)
28
+ c = c.where(:queue => queues) unless queues.empty?
29
+ c.count
30
+ elsif defined?(Mongoid)
31
+ c = ::Delayed::Job
32
+ c = c.where(:failed_at => nil)
33
+ c = c.where(:run_at.lte => Time.now.utc)
34
+ c = c.where(:queue.in => queues) unless queues.empty?
35
+ c.count
36
+ else
37
+ raise "HireFire could not detect ActiveRecord or Mongoid for HireFire::Macro::Delayed::Job."
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+
@@ -0,0 +1,24 @@
1
+ # encoding: utf-8
2
+
3
+ module HireFire
4
+ module Macro
5
+ module QC
6
+ extend self
7
+
8
+ # Queries the PostgreSQL database through QueueClassic in order to
9
+ # count the amount of jobs in the specified queue.
10
+ #
11
+ # Example:
12
+ #
13
+ # HireFire::Macro::QC.queue # counts the `default` queue.
14
+ # HireFire::Macro::QC.queue("email") # counts the `email` queue.
15
+ #
16
+ # @param [String, Symbol, nil] queue the queue name to count. (default: `default`)
17
+ # @return [Integer] the number of jobs in the queue(s).
18
+ def queue(queue = "default")
19
+ ::QC::Queries.count(queue.to_s)
20
+ end
21
+ end
22
+ end
23
+ end
24
+
@@ -0,0 +1,25 @@
1
+ # encoding: utf-8
2
+
3
+ module HireFire
4
+ module Macro
5
+ module Qu
6
+ extend self
7
+
8
+ # Counts the amount of jobs in the (provided) Qu queue(s).
9
+ #
10
+ # Example:
11
+ #
12
+ # HireFire::Macro::Qu.queue # all queues
13
+ # HireFire::Macro::Qu.queue("email") # only email queue
14
+ # HireFire::Macro::Qu.queue("audio", "video") # audio and video queues
15
+ #
16
+ # @param [Array] queues provide one or more queue names, or none for "all".
17
+ # @return [Integer] the number of jobs in the queue(s).
18
+ def queue(*queues)
19
+ queues = ::Qu.backend.queues if queues.empty?
20
+ queues.flatten.inject(0) { |memo, queue| memo += ::Qu.backend.length(queue); memo }
21
+ end
22
+ end
23
+ end
24
+ end
25
+
@@ -0,0 +1,26 @@
1
+ # encoding: utf-8
2
+
3
+ module HireFire
4
+ module Macro
5
+ module Resque
6
+ extend self
7
+
8
+ # Counts the amount of jobs in the (provided) Resque queue(s).
9
+ #
10
+ # Example:
11
+ #
12
+ # HireFire::Macro::Resque.queue # all queues
13
+ # HireFire::Macro::Resque.queue("email") # only email queue
14
+ # HireFire::Macro::Resque.queue("audio", "video") # audio and video queues
15
+ #
16
+ # @param [Array] queues provide one or more queue names, or none for "all".
17
+ # @return [Integer] the number of jobs in the queue(s).
18
+ def queue(*queues)
19
+ return ::Resque.info[:pending].to_i if queues.empty?
20
+ queues = queues.flatten.map(&:to_s)
21
+ queues.inject(0) { |memo, queue| memo += ::Resque.size(queue); memo }
22
+ end
23
+ end
24
+ end
25
+ end
26
+
@@ -0,0 +1,73 @@
1
+ # encoding: utf-8
2
+
3
+ module HireFire
4
+ class Middleware
5
+
6
+ # Initialize the HireFire::Middleware and store the `app` in `@app`
7
+ # and `ENV["HIREFIRE_TOKEN"]` in `@token` for convenience.
8
+ #
9
+ # @param [ActionDispatch::Routing::RouteSet] app.
10
+ def initialize(app)
11
+ @app = app
12
+ @token = ENV["HIREFIRE_TOKEN"]
13
+ end
14
+
15
+ # Will respond to the request here if either the `test` or the `info` url was requested.
16
+ # Otherwise, fall through to the rest of the middleware below HireFire::Middleware.
17
+ #
18
+ # @param [Hash] env containing request information.
19
+ def call(env)
20
+ @env = env
21
+
22
+ if test?
23
+ [ 200, {"Content-Type" => "text/html"}, self ]
24
+ elsif info?
25
+ [ 200, {"Content-Type" => "application/json"}, self ]
26
+ else
27
+ @app.call(env)
28
+ end
29
+ end
30
+
31
+ # Returns text/html when the `test` url is requested.
32
+ # This is purely to see whether the URL works through the HireFire command-line utility.
33
+ #
34
+ # Returns a JSON String when the `info` url is requested.
35
+ # This url will be requested every minute by HireFire in order to fetch dyno data.
36
+ #
37
+ # @return [text/html, application/json] based on whether the `test` or `info` url was requested.
38
+ def each(&block)
39
+ if test?
40
+ block.call "HireFire Middleware Found!"
41
+ elsif info?
42
+ block.call(dynos)
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ # Generates a JSON string based on the dyno data.
49
+ #
50
+ # @return [String] in JSON format.
51
+ def dynos
52
+ dyno_data = HireFire::Resource.dynos.inject(String.new) do |json, dyno|
53
+ json << %|,{"name":"#{dyno[:name]}","quantity":#{dyno[:quantity].call || "null"}}|; json
54
+ end
55
+
56
+ "[#{dyno_data.sub(",","")}]"
57
+ end
58
+
59
+ # Returns true if the PATH_INFO matches the test url.
60
+ #
61
+ # @return [Boolean] true if the requested url matches the test url.
62
+ def test?
63
+ @env["PATH_INFO"] == "/hirefire/test"
64
+ end
65
+
66
+ # Returns true if the PATH_INFO matches the info url.
67
+ #
68
+ # @return [Boolean] true if the requested url matches the info url.
69
+ def info?
70
+ @env["PATH_INFO"] == "/hirefire/#{@token || "development"}/info"
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,9 @@
1
+ # encoding: utf-8
2
+
3
+ module HireFire
4
+ class Railtie < ::Rails::Railtie
5
+ initializer "hirefire.add_middleware" do |app|
6
+ app.config.middleware.use "HireFire::Middleware"
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,33 @@
1
+ # encoding: utf-8
2
+
3
+ module HireFire
4
+ module Resource
5
+ extend self
6
+ attr_accessor :dynos
7
+
8
+ # Sets the `@dynos` instance variable to an empty Array to hold all the dyno configuration.
9
+ #
10
+ # Example:
11
+ #
12
+ # HireFire::Resource.configure do |config|
13
+ # config.dyno(:worker) do
14
+ # # Macro or Custom logic for the :worker dyno here..
15
+ # end
16
+ # end
17
+ #
18
+ # @yields [HireFire::Resource] to allow for block-style configuration.
19
+ def configure
20
+ @dynos ||= []
21
+ yield self
22
+ end
23
+
24
+ # Will be used through block-style configuration with the `configure` method.
25
+ #
26
+ # @param [Symbol, String] name the name of the dyno as defined in the Procfile.
27
+ # @param [Proc] block an Integer containing the quantity calculation logic.
28
+ def dyno(name, &block)
29
+ @dynos << { :name => name, :quantity => block }
30
+ end
31
+ end
32
+ end
33
+
metadata ADDED
@@ -0,0 +1,61 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hirefire-resource
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Michael van Rooijen
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-07-20 00:00:00.000000000 Z
13
+ dependencies: []
14
+ description: HireFire - The Heroku Dyno Manager
15
+ email: michael@hirefireapp.com
16
+ executables:
17
+ - hirefire
18
+ - hirefireapp
19
+ extensions: []
20
+ extra_rdoc_files: []
21
+ files:
22
+ - .gitignore
23
+ - README.md
24
+ - bin/hirefire
25
+ - bin/hirefireapp
26
+ - hirefire-resource.gemspec
27
+ - lib/hirefire-resource.rb
28
+ - lib/hirefire/cli.rb
29
+ - lib/hirefire/macro/delayed_job.rb
30
+ - lib/hirefire/macro/qc.rb
31
+ - lib/hirefire/macro/qu.rb
32
+ - lib/hirefire/macro/resque.rb
33
+ - lib/hirefire/middleware.rb
34
+ - lib/hirefire/railtie.rb
35
+ - lib/hirefire/resource.rb
36
+ homepage: http://hirefireapp.com/
37
+ licenses: []
38
+ post_install_message:
39
+ rdoc_options: []
40
+ require_paths:
41
+ - lib
42
+ required_ruby_version: !ruby/object:Gem::Requirement
43
+ none: false
44
+ requirements:
45
+ - - ! '>='
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ required_rubygems_version: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ! '>='
52
+ - !ruby/object:Gem::Version
53
+ version: '0'
54
+ requirements: []
55
+ rubyforge_project:
56
+ rubygems_version: 1.8.16
57
+ signing_key:
58
+ specification_version: 3
59
+ summary: HireFire - The Heroku Dyno Manager
60
+ test_files: []
61
+ has_rdoc: