hirefire-resource 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +4 -0
- data/README.md +80 -0
- data/bin/hirefire +4 -0
- data/bin/hirefireapp +5 -0
- data/hirefire-resource.gemspec +17 -0
- data/lib/hirefire-resource.rb +14 -0
- data/lib/hirefire/cli.rb +48 -0
- data/lib/hirefire/macro/delayed_job.rb +44 -0
- data/lib/hirefire/macro/qc.rb +24 -0
- data/lib/hirefire/macro/qu.rb +25 -0
- data/lib/hirefire/macro/resque.rb +26 -0
- data/lib/hirefire/middleware.rb +73 -0
- data/lib/hirefire/railtie.rb +9 -0
- data/lib/hirefire/resource.rb +33 -0
- metadata +61 -0
data/.gitignore
ADDED
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
data/bin/hirefireapp
ADDED
@@ -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
|
+
|
data/lib/hirefire/cli.rb
ADDED
@@ -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,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:
|