resque-top 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,4 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in resque-top.gemspec
4
+ gemspec
@@ -0,0 +1,7 @@
1
+ Copyright (C) 2012 Tatsuhiko Miyagawa
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,38 @@
1
+ # resque-top
2
+
3
+ resque-top is a top-like command line utility to display resque queue and worker status, like [resque-web](https://github.com/defunkt/resque).
4
+
5
+ ## Screenshot
6
+
7
+ ![](http://dl.dropbox.com/u/135035/Screenshots/y1tyvv6uihcl.png)
8
+
9
+
10
+ ## Installation
11
+
12
+ ### github
13
+
14
+ ```
15
+ git clone git://github.com/miyagawa/resque-top.git
16
+ gem build resque-top.gemspec
17
+ gem install resque-top-<version>.gem
18
+ ```
19
+
20
+ ## Usage
21
+
22
+ ```
23
+ resque-top -N <namespace>
24
+ resque-top -r <hostname>:<port>/<namespace>
25
+ ```
26
+
27
+ ## Author
28
+
29
+ Tatsuhiko Miyagawa (@miyagawa)
30
+
31
+ ## License
32
+
33
+ MIT License
34
+
35
+
36
+
37
+
38
+
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'slop'
4
+ argv = ARGV.dup
5
+ slop = Slop.new :strict => true, :help => true
6
+ slop.banner "Usage: resque-top [options]\n"
7
+ slop.on '-N', :namespace=, 'set the Redis namespace'
8
+ slop.on '-r', :redis=, 'set the Redis connection string'
9
+
10
+ begin
11
+ slop.parse! argv
12
+ rescue => e
13
+ puts e
14
+ exit!
15
+ end
16
+
17
+ options = slop.to_hash
18
+ options.delete(:help)
19
+
20
+ $:.unshift File.dirname(__FILE__) + '/../lib' if $0 == __FILE__
21
+ require 'resque-top'
22
+ Resque::Top::CLI.new(options).run
@@ -0,0 +1,2 @@
1
+ require "resque-top/version"
2
+ require "resque-top/cli"
@@ -0,0 +1,123 @@
1
+ require 'resque'
2
+
3
+ module Resque::Top
4
+ class CLI
5
+ def initialize(options)
6
+ if options[:redis]
7
+ Resque.redis = options[:redis]
8
+ end
9
+ if options[:namespace]
10
+ Resque.redis.namespace = options[:namespace]
11
+ end
12
+
13
+ @width, @height = detect_terminal_size
14
+ end
15
+
16
+ def run
17
+ loop do
18
+ display
19
+ sleep 1
20
+ end
21
+ rescue Interrupt
22
+ end
23
+
24
+ def right_float(target, str)
25
+ target << (' ' * (@width - target.length - str.length)) + str
26
+ end
27
+
28
+ def tabular(rows, indent=2, separator="|")
29
+ if rows.empty?
30
+ nil
31
+ else
32
+ longest = [0] * rows[0].count
33
+ rows.each do |cols|
34
+ cols.each_with_index do |value, i|
35
+ longest[i] = [ longest[i], value.to_s.length ].max
36
+ end
37
+ end
38
+ rows.collect do |row|
39
+ longest.each_with_index do |value, i|
40
+ row[i] = justify(value, row[i])
41
+ end
42
+ (" " * indent) + row.join(" | ")
43
+ end
44
+ end
45
+ end
46
+
47
+ def justify(longest, string)
48
+ if string.is_a?(Integer)
49
+ string.to_s.rjust(longest)
50
+ else
51
+ string.ljust(longest)
52
+ end
53
+ end
54
+
55
+ def display
56
+ out = []
57
+ out << "Resque connected to: #{Resque.redis_id} (#{Resque.redis.namespace})"
58
+ out << ""
59
+
60
+ out << "Queues: "
61
+ rows = []
62
+ Resque.queues.each do |queue|
63
+ rows << [ queue, Resque.size(queue) ]
64
+ end
65
+ rows << [ "failed", Resque::Failure.count ]
66
+ out.push *(tabular(rows))
67
+
68
+ out << ""
69
+
70
+ out << "Workers:"
71
+ workers = Resque.workers.sort_by { |w| w.to_s }
72
+
73
+ workers.each do |worker|
74
+ line = ''
75
+ host, pid, queues = worker.to_s.split(':')
76
+ cols = []
77
+ cols << [ "#{host}:#{pid}", queues ]
78
+ data = worker.processing || {}
79
+ if data['queue']
80
+ cols[-1].push "#{data['payload']['class']} (#{data['run_at']})"
81
+ else
82
+ cols[-1].push "Waiting for a job...."
83
+ end
84
+ out.push *(tabular(cols))
85
+ end
86
+
87
+ if workers.empty?
88
+ out << " (There are no registered workers)"
89
+ end
90
+
91
+ (@height - out.size - 2).times do out << "" end
92
+ out << "(Ctrl-c to quit.)"
93
+
94
+ right_float(out[0], Time.now.strftime('%H:%M:%S'))
95
+
96
+ clear
97
+ puts out.join("\n")
98
+ end
99
+
100
+ def clear
101
+ print "\033[2J"
102
+ end
103
+
104
+ def command_exists?(command)
105
+ ENV['PATH'].split(File::PATH_SEPARATOR).any? { |d| File.exists? File.join(d, command) }
106
+ end
107
+
108
+ # https://github.com/cldwalker/hirb/blob/master/lib/hirb/util.rb#L61-71
109
+ def detect_terminal_size
110
+ if (ENV['COLUMNS'] =~ /^\d+$/) && (ENV['LINES'] =~ /^\d+$/)
111
+ [ENV['COLUMNS'].to_i, ENV['LINES'].to_i]
112
+ elsif (RUBY_PLATFORM =~ /java/ || (!STDIN.tty? && ENV['TERM'])) && command_exists?('tput')
113
+ [`tput cols`.to_i, `tput lines`.to_i]
114
+ elsif STDIN.tty? && command_exists?('stty')
115
+ `stty size`.scan(/\d+/).map { |s| s.to_i }.reverse
116
+ else
117
+ nil
118
+ end
119
+ rescue Exception => e
120
+ nil
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,5 @@
1
+ module Resque
2
+ module Top
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,25 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "resque-top/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "resque-top"
7
+ s.version = Resque::Top::VERSION
8
+ s.authors = ["Tatsuhiko Miyagawa"]
9
+ s.email = ["miyagawa@bulknews.net"]
10
+ s.homepage = "https://github.com/miyagawa/resque-top"
11
+ s.summary = %q{top for Resque}
12
+ s.description = s.summary
13
+
14
+ s.rubyforge_project = "resque-top"
15
+
16
+ s.files = `git ls-files`.split("\n")
17
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
18
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
19
+ s.require_paths = ["lib"]
20
+
21
+ # specify any dependencies here; for example:
22
+ # s.add_development_dependency "rspec"
23
+ s.add_runtime_dependency "resque"
24
+ s.add_runtime_dependency "slop", "~> 2.0"
25
+ end
metadata ADDED
@@ -0,0 +1,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: resque-top
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Tatsuhiko Miyagawa
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-03-04 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: resque
16
+ requirement: &70110119484840 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *70110119484840
25
+ - !ruby/object:Gem::Dependency
26
+ name: slop
27
+ requirement: &70110119484260 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ~>
31
+ - !ruby/object:Gem::Version
32
+ version: '2.0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *70110119484260
36
+ description: top for Resque
37
+ email:
38
+ - miyagawa@bulknews.net
39
+ executables:
40
+ - resque-top
41
+ extensions: []
42
+ extra_rdoc_files: []
43
+ files:
44
+ - .gitignore
45
+ - Gemfile
46
+ - LICENSE.txt
47
+ - README.md
48
+ - Rakefile
49
+ - bin/resque-top
50
+ - lib/resque-top.rb
51
+ - lib/resque-top/cli.rb
52
+ - lib/resque-top/version.rb
53
+ - resque-top.gemspec
54
+ homepage: https://github.com/miyagawa/resque-top
55
+ licenses: []
56
+ post_install_message:
57
+ rdoc_options: []
58
+ require_paths:
59
+ - lib
60
+ required_ruby_version: !ruby/object:Gem::Requirement
61
+ none: false
62
+ requirements:
63
+ - - ! '>='
64
+ - !ruby/object:Gem::Version
65
+ version: '0'
66
+ required_rubygems_version: !ruby/object:Gem::Requirement
67
+ none: false
68
+ requirements:
69
+ - - ! '>='
70
+ - !ruby/object:Gem::Version
71
+ version: '0'
72
+ requirements: []
73
+ rubyforge_project: resque-top
74
+ rubygems_version: 1.8.15
75
+ signing_key:
76
+ specification_version: 3
77
+ summary: top for Resque
78
+ test_files: []
79
+ has_rdoc: