Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

We’re showing branches in this repository, but you can also compare across forks.

base fork: resque/resque
...
head fork: processone/resque
  • 10 commits
  • 25 files changed
  • 1 commit comment
  • 1 contributor
Showing with 892 additions and 353 deletions.
  1. +26 −96 lib/resque/server.rb
  2. +93 −0 lib/resque/server/helpers.rb
  3. +12 −0 lib/resque/server/templates/_stats_table.mustache
  4. +25 −0 lib/resque/server/templates/key_sets.mustache
  5. +13 −0 lib/resque/server/templates/key_string.mustache
  6. +49 −0 lib/resque/server/templates/layout.mustache
  7. +10 −0 lib/resque/server/templates/next_more.mustache
  8. +73 −0 lib/resque/server/templates/queues.mustache
  9. +35 −0 lib/resque/server/templates/stats.mustache
  10. +99 −0 lib/resque/server/templates/workers.mustache
  11. +36 −24 lib/resque/server/{views/working.erb → templates/working.mustache}
  12. +1 −1  lib/resque/server/views/failed.erb
  13. +0 −20 lib/resque/server/views/key_sets.erb
  14. +0 −11 lib/resque/server/views/key_string.erb
  15. +82 −0 lib/resque/server/views/layout.rb
  16. +0 −10 lib/resque/server/views/next_more.erb
  17. +2 −2 lib/resque/server/views/overview.erb
  18. +0 −49 lib/resque/server/views/queues.erb
  19. +69 −0 lib/resque/server/views/queues.rb
  20. +0 −62 lib/resque/server/views/stats.erb
  21. +134 −0 lib/resque/server/views/stats.rb
  22. +47 −0 lib/resque/server/views/worker_list.rb
  23. +0 −78 lib/resque/server/views/workers.erb
  24. +35 −0 lib/resque/server/views/workers.rb
  25. +51 −0 lib/resque/server/views/working.rb
122 lib/resque/server.rb
View
@@ -1,113 +1,43 @@
-require 'sinatra/base'
require 'erb'
+
+require 'sinatra/base'
+require 'mustache/sinatra'
+
require 'resque'
require 'resque/version'
+require 'resque/server/helpers'
+require 'resque/server/views/layout'
+require 'resque/server/views/worker_list'
+
module Resque
class Server < Sinatra::Base
+ register Mustache::Sinatra
+ helpers Helpers
+
dir = File.dirname(File.expand_path(__FILE__))
set :views, "#{dir}/server/views"
set :public, "#{dir}/server/public"
set :static, true
- helpers do
- include Rack::Utils
- alias_method :h, :escape_html
-
- def current_section
- url request.path_info.sub('/','').split('/')[0].downcase
- end
-
- def current_page
- url request.path_info.sub('/','').downcase
- end
-
- def url(*path_parts)
- [ path_prefix, path_parts ].join("/").squeeze('/')
- end
- alias_method :u, :url
-
- def path_prefix
- request.env['SCRIPT_NAME']
- end
-
- def class_if_current(path = '')
- 'class="current"' if current_page[0, path.size] == path
- end
-
- def tab(name)
- dname = name.to_s.downcase
- path = url(dname)
- "<li #{class_if_current(path)}><a href='#{path}'>#{name}</a></li>"
- end
-
- def tabs
- Resque::Server.tabs
- end
-
- def redis_get_size(key)
- case Resque.redis.type(key)
- when 'none'
- []
- when 'list'
- Resque.redis.llen(key)
- when 'set'
- Resque.redis.scard(key)
- when 'string'
- Resque.redis.get(key).length
- when 'zset'
- Resque.redis.zcard(key)
- end
- end
-
- def redis_get_value_as_array(key, start=0)
- case Resque.redis.type(key)
- when 'none'
- []
- when 'list'
- Resque.redis.lrange(key, start, start + 20)
- when 'set'
- Resque.redis.smembers(key)[start..(start + 20)]
- when 'string'
- [Resque.redis.get(key)]
- when 'zset'
- Resque.redis.zrange(key, start, start + 20)
- end
- end
-
- def show_args(args)
- Array(args).map { |a| a.inspect }.join("\n")
- end
-
- def partial?
- @partial
- end
-
- def partial(template, local_vars = {})
- @partial = true
- erb(template.to_sym, {:layout => false}, local_vars)
- ensure
- @partial = false
- end
-
- def poll
- if @polling
- text = "Last Updated: #{Time.now.strftime("%H:%M:%S")}"
- else
- text = "<a href='#{url(request.path_info)}.poll' rel='poll'>Live Poll</a>"
- end
- "<p class='poll'>#{text}</p>"
- end
-
- end
+ set :mustache, {
+ :namespace => Resque,
+ :templates => "#{dir}/server/templates",
+ :views => "#{dir}/server/views"
+ }
def show(page, layout = true)
- begin
+ templates = settings.mustache[:templates]
+
+ if File.exists? "#{templates}/#{page}.mustache"
+ mustache page.to_sym
+ else
erb page.to_sym, {:layout => layout}, :resque => Resque
- rescue Errno::ECONNREFUSED
- erb :error, {:layout => false}, :error => "Can't connect to Redis! (#{Resque.redis.server})"
end
+ rescue Errno::ECONNREFUSED
+ erb :error, { :layout => false },
+ :error => "Can't connect to Redis! (#{Resque.redis.server})"
end
# to make things easier on ourselves
@@ -124,7 +54,7 @@ def show(page, layout = true)
show page
end
end
-
+
post "/queues/:id/remove" do
Resque.remove_queue(params[:id])
redirect u('queues')
@@ -150,7 +80,7 @@ def show(page, layout = true)
Resque::Failure.clear
redirect u('failed')
end
-
+
get "/failed/requeue/:index" do
Resque::Failure.requeue(params[:index])
redirect u('failed')
93 lib/resque/server/helpers.rb
View
@@ -0,0 +1,93 @@
+module Resque
+ class Server < Sinatra::Base
+ module Helpers
+ include Rack::Utils
+ alias_method :h, :escape_html
+
+ def current_section
+ url request.path_info.sub('/','').split('/')[0].downcase
+ end
+
+ def current_page
+ url request.path_info.sub('/','').downcase
+ end
+
+ def url(*path_parts)
+ [ path_prefix, path_parts ].join("/").squeeze('/')
+ end
+ alias_method :u, :url
+
+ def path_prefix
+ request.env['SCRIPT_NAME']
+ end
+
+ def class_if_current(path = '')
+ 'class="current"' if current_page[0, path.size] == path
+ end
+
+ def tab(name)
+ dname = name.to_s.downcase
+ path = url(dname)
+ "<li #{class_if_current(path)}><a href='#{path}'>#{name}</a></li>"
+ end
+
+ def tabs
+ Resque::Server.tabs
+ end
+
+ def redis_get_size(key)
+ case Resque.redis.type(key)
+ when 'none'
+ []
+ when 'list'
+ Resque.redis.llen(key)
+ when 'set'
+ Resque.redis.scard(key)
+ when 'string'
+ Resque.redis.get(key).length
+ when 'zset'
+ Resque.redis.zcard(key)
+ end
+ end
+
+ def redis_get_value_as_array(key, start=0)
+ case Resque.redis.type(key)
+ when 'none'
+ []
+ when 'list'
+ Resque.redis.lrange(key, start, start + 20)
+ when 'set'
+ Resque.redis.smembers(key)[start..(start + 20)]
+ when 'string'
+ [Resque.redis.get(key)]
+ when 'zset'
+ Resque.redis.zrange(key, start, start + 20)
+ end
+ end
+
+ def show_args(args)
+ Array(args).map { |a| a.inspect }.join("\n")
+ end
+
+ def partial?
+ @partial
+ end
+
+ def erb_partial(template, local_vars = {})
+ @partial = true
+ erb(template.to_sym, {:layout => false}, local_vars)
+ ensure
+ @partial = false
+ end
+
+ def poll
+ if @polling
+ text = "Last Updated: #{Time.now.strftime("%H:%M:%S")}"
+ else
+ text = "<a href='#{url(request.path_info)}.poll' rel='poll'>Live Poll</a>"
+ end
+ "<p class='poll'>#{text}</p>"
+ end
+ end
+ end
+end
12 lib/resque/server/templates/_stats_table.mustache
View
@@ -0,0 +1,12 @@
+<table class='stats'>
+ {{# stats }}
+ <tr>
+ <th>
+ {{ key }}
+ </th>
+ <td>
+ {{ value }}
+ </td>
+ </tr>
+ {{/ stats }}
+</table>
25 lib/resque/server/templates/key_sets.mustache
View
@@ -0,0 +1,25 @@
+{{#set_key_page?}}
+ <p class='sub'>
+ Showing
+ {{start}}
+ to
+ {{end}}
+ of
+ <b>
+ {{size}}
+ </b>
+ </p>
+
+ <h1>Key "{{key}}" is a {{key_type}}</h1>
+ <table>
+ {{#key_as_array}}
+ <tr>
+ <td>
+ {{row}}
+ </td>
+ </tr>
+ {{/key_as_array}}
+ </table>
+
+ {{> next_more}}
+{{/set_key_page?}}
13 lib/resque/server/templates/key_string.mustache
View
@@ -0,0 +1,13 @@
+{{#key_page?}}
+
+ <h1>Key "{{key}}" is a {{key_type}}</h1>
+ <h2>size: {{key_size}}</h2>
+ <table>
+ <tr>
+ <td>
+ {{key_value_as_array}}
+ </td>
+ </tr>
+ </table>
+
+{{/key_page?}}
49 lib/resque/server/templates/layout.mustache
View
@@ -0,0 +1,49 @@
+<!DOCTYPE html>
+<html lang="en">
+<head>
+ <meta charset="utf-8" />
+ <title>Resque.</title>
+ {{{reset_css}}}
+ {{{style_css}}}
+ {{{jquery_js}}}
+ {{{relatize_js}}}
+ {{{ranger_js}}}
+</head>
+<body>
+ <div class="header">
+ <ul class='nav'>
+ {{#tabs}}
+ {{{tab}}}
+ {{/tabs}}
+ </ul>
+ {{#custom_namespace?}}
+ <abbr class="namespace" title="Resque's Redis Namespace">
+ {{namespace}}
+ </abbr>
+ {{/custom_namespace?}}
+ </div>
+
+{{#any_subtabs?}}
+ <ul class='subnav'>
+ {{#keyed_subtabs}}
+ <li {{{class}}}>
+ <a href="{{current_section}}/{{subtab}}">
+ <span>{{subtab}}</span>
+ </a>
+ </li>
+ {{/keyed_subtabs}}
+ </ul>
+{{/any_subtabs?}}
+
+<div id="main">
+ {{{yield}}}
+</div>
+
+<div id="footer">
+ <p>Powered by <a href="http://github.com/defunkt/resque">Resque</a>
+ v{{version}}<%=%></p>
+ <p>Connected to Redis namespace {{namespace}} on {{redis_server}}</p>
+</div>
+
+</body>
+</html>
10 lib/resque/server/templates/next_more.mustache
View
@@ -0,0 +1,10 @@
+{{#pagination?}}
+<p class='pagination'>
+ {{#less_page?}}
+ <a href="{{current_page}}?start={{start_less}}" class='less'>&laquo; less</a>
+ {{/less_page?}}
+ {{#more_page?}}
+ <a href="{{current_page}}?start={{start_more}}" class='more'>more &raquo;</a>
+ {{/more_page?}}
+</p>
+{{/pagination?}}
73 lib/resque/server/templates/queues.mustache
View
@@ -0,0 +1,73 @@
+{{#queue?}}
+ <h1>Pending jobs on <span class='hl'>{{queue}}</span></h1>
+
+ <form method="POST" action="{{remove_queue_url}}" class='remove-queue'>
+ <input type='submit' name='' value='Remove Queue' />
+ </form>
+
+ <p class='sub'>
+ Showing {{start}}
+ to
+ {{end}}
+ of
+ <b>{{size}}</b>
+ jobs
+ </p>
+
+ <table class='jobs'>
+ <tr>
+ <th>Class</th>
+ <th>Args</th>
+ </tr>
+
+ {{#jobs}}
+ <tr>
+ <td class='class'>{{class}}</td>
+ <td class='args'>{{args}}</td>
+ </tr>
+ {{/jobs}}
+
+ {{#no_jobs}}
+ <tr>
+ <td class='no-data' colspan='2'>
+ There are no pending jobs in this queue
+ </td>
+ </tr>
+ {{/no_jobs}}
+ </table>
+
+ {{> next_more}}
+{{/queue?}}
+
+{{#queues?}}
+ <h1 class='wi'>Queues</h1>
+
+ <p class='intro'>
+ The list below contains all the registered queues with the number
+ of jobs currently in the queue. Select a queue from above to view
+ all jobs currently pending on the queue.
+ </p>
+
+ <table class='queues'>
+ <tr>
+ <th>Name</th>
+ <th>Jobs</th>
+ </tr>
+
+ {{#queues}}
+ <tr>
+ <td class='queue'>
+ <a class="queue" href="{{queue_url}}">{{queue}}</a>
+ </td>
+ <td class='size'>{{size}}</td>
+ </tr>
+ {{/queues}}
+
+ <tr class="{{failure_class}}">
+ <td class='queue failed'>
+ <a class="queue" href="{{failed_url}}">failed</a>
+ </td>
+ <td class='size'>{{failed_count}}</td>
+ </tr>
+ </table>
+{{/queues?}}
35 lib/resque/server/templates/stats.mustache
View
@@ -0,0 +1,35 @@
+{{#resque_page?}}
+ <h1>{{resque}}</h1>
+ {{>_stats_table}}
+{{/resque_page?}}
+
+{{#redis_page?}}
+ <h1>{{redis_server}}</h1>
+ {{>_stats_table}}
+{{/redis_page?}}
+
+{{#keys_page?}}
+ <h1>Keys owned by {{resque}}</h1>
+ <p class='sub'>(All keys are actually prefixed with "resque:")</p>
+ <table class='stats'>
+ <tr>
+ <th>key</th>
+ <th>type</th>
+ <th>size</th>
+ </tr>
+ {{#keys}}
+ <tr>
+ <th>
+ <a href="{{href}}">{{name}}</a>
+ </th>
+ <td>{{type}}</td>
+ <td>{{size}}</td>
+ </tr>
+ {{/keys}}
+ </table>
+{{/keys_page?}}
+
+{{#key_page?}}
+ {{>key_string_or_sets}}
+{{/key_page?}}
+
99 lib/resque/server/templates/workers.mustache
View
@@ -0,0 +1,99 @@
+{{#worker?}}
+ <h1>Worker {{to_s}}</h1>
+ <table class='workers'>
+ <tr>
+ <th>&nbsp;</th>
+ <th>Host</th>
+ <th>Pid</th>
+ <th>Started</th>
+ <th>Queues</th>
+ <th>Processed</th>
+ <th>Failed</th>
+ <th>Processing</th>
+ </tr>
+ <tr>
+ <td class='icon'>
+ {{{state_icon}}}
+
+ <% host, pid, queues = worker.to_s.split(':') %>
+ <td>{{worker_host}}</td>
+ <td>{{worker_pid}}</td>
+ <td><span class="time">{{started}}</span></td>
+ <td class='queues'>
+ {{linked_queues}}
+ </td>
+ <td>{{processed}}</td>
+ <td>{{failed}}></td>
+ <td class='process'>
+ {{#processing}}
+ {{#data}}
+ <code>{{#payload}}{{class}}{{/payload}}</code>
+ <small>
+ <a class="queue time" href="{{working_url}}">{{run_at}}</a>
+ </small>
+ {{/data}}
+ {{/processing}}
+
+ {{#not_processing}}
+ <span class='waiting'>Waiting for a job...</span>
+ {{/not_processing}}
+ </td>
+ </tr>
+ </table>
+{{/worker?}}
+
+{{#worker_not_found?}}
+ <h1>Worker doesn't exist</h1>
+{{/worker_not_found?}}
+
+{{#all_workers?}}
+ <h1 class='wi'>{{size}} Workers</h1>
+ <p class='intro'>
+ The workers listed below are all registered as active on your system.
+ </p>
+
+ <table class='workers'>
+ <tr>
+ <th>&nbsp;</th>
+ <th>Where</th>
+ <th>Queues</th>
+ <th>Processing</th>
+ </tr>
+ {{#workers}}
+ <tr class="{{state}}">
+ <td class='icon'>
+ {{{state_icon}}}
+ </td>
+
+ <td class='where'>
+ <a href="{{worker_url}}">{{worker_host}}:{{worker_pid}}</a></td>
+ <td class='queues'>
+ {{{linked_queues}}}
+ </td>
+
+ <td class='process'>
+ {{#processing}}
+ {{#queue}}
+ <code>{{#payload}}{{class}}{{/payload}}</code>
+ <small>
+ <a class="queue time" href="{{working_url}}">{{run_at}}</a>
+ </small>
+ {{/queue}}
+ {{/processing}}
+
+ {{#not_processing}}
+ <span class='waiting'>Waiting for a job...</span>
+ {{/not_processing}}
+ </td>
+ </tr>
+ {{/workers}}
+
+ {{#no_workers?}}
+ <tr>
+ <td colspan='4' class='no-data'>There are no registered workers</td>
+ </tr>
+ {{/no_workers?}}
+ </table>
+
+ <%=poll%>
+{{/all_workers?}}
60 lib/resque/server/views/working.erb → lib/resque/server/templates/working.mustache
View
@@ -1,5 +1,5 @@
-<% if params[:id] && (worker = Resque::Worker.find(params[:id])) && worker.job %>
- <h1><%= worker %>'s job</h1>
+{{#single_worker?}}
+ <h1>{{to_s}}'s job</h1>
<table>
<tr>
@@ -25,11 +25,13 @@
</tr>
</table>
-<% else %>
+{{/single_worker?}}
- <% workers = resque.working %>
- <h1 class='wi'><%= workers.size %> of <%= resque.workers.size %> Workers Working</h1>
- <p class='intro'>The list below contains all workers which are currently running a job.</p>
+{{#all_workers?}}
+ <h1 class='wi'>{{workers_working}} of {{workers_total}} Workers Working</h1>
+ <p class='intro'>
+ The list below contains all workers which are currently running a job.
+ </p>
<table class='workers'>
<tr>
<th>&nbsp;</th>
@@ -37,33 +39,43 @@
<th>Queue</th>
<th>Processing</th>
</tr>
- <% if workers.empty? %>
+
+ {{#none_working?}}
<tr>
<td colspan="4" class='no-data'>Nothing is happening right now...</td>
</tr>
- <% end %>
-
- <% for worker in workers.sort_by { |w| w.job['run_at'] ? w.job['run_at'] : '' } %>
- <% job = worker.job %>
- <% next if worker.idle? %>
+ {{/none_working?}}
+ {{#working}}
<tr>
- <td class='icon'><img src="<%=u state = worker.state %>.png" alt="<%= state %>" title="<%= state %>"></td>
- <% host, pid, queues = worker.to_s.split(':') %>
- <td class='where'><a href="<%=u "/workers/#{worker}" %>"><%= host %>:<%= pid %></a></td>
+ <td class='icon'>
+ <img src="{{state_icon}}" alt="{{state}}" title="{{state}}">
+ </td>
+
+ <td class='where'>
+ <a href="{{worker_url}}">{{worker_host}}:{{worker_pid}}</a>
+ </td>
+
<td class='queues queue'>
- <a class="queue-tag" href="<%=u "/queues/#{job['queue']}" %>"><%= job['queue'] %></a>
+ {{#job}}
+ <a class="queue-tag" href="{{queue_url}}">
+ {{queue}}
+ {{/job}}
+ </a>
</td>
+
<td class='process'>
- <% if job['queue'] %>
- <code><%= job['payload']['class'] %></code>
- <small><a class="queue time" href="<%=u "/working/#{worker}" %>"><%= job['run_at'] %></a></small>
- <% else %>
+ {{#job}}
+ <code>{{#payload}}{{class}}{{/payload}}</code>
+ <small>
+ <a class="queue time" href="{{working_url}}">{{run_at}}</a>
+ </small>
+ {{/job}}
+ {{#no_job}}
<span class='waiting'>Waiting for a job...</span>
- <% end %>
+ {{/no_job}}
</td>
</tr>
- <% end %>
+ {{/working}}
</table>
-
-<% end %>
+{{/all_workers?}}
2  lib/resque/server/views/failed.erb
View
@@ -45,4 +45,4 @@
<%end%>
</ul>
-<%= partial :next_more, :start => start, :size => size %>
+<%= erb_partial :next_more, :start => start, :size => size %>
20 lib/resque/server/views/key_sets.erb
View
@@ -1,20 +0,0 @@
-<% if key = params[:key] %>
-
- <p class='sub'>
- Showing <%= start = params[:start].to_i %> to <%= start + 20 %> of <b><%=size = redis_get_size(key) %></b>
- </p>
-
-
- <h1>Key "<%= key %>" is a <%= resque.redis.type key %></h1>
- <table>
- <% for row in redis_get_value_as_array(key, start) %>
- <tr>
- <td>
- <%= row %>
- </td>
- </tr>
- <% end %>
- </table>
-
-<%= partial :next_more, :start => start, :size => size %>
-<% end %>
11 lib/resque/server/views/key_string.erb
View
@@ -1,11 +0,0 @@
-<% if key = params[:key] %>
- <h1>Key "<%= key %>" is a <%= resque.redis.type key %></h1>
- <h2>size: <%= redis_get_size(key) %></h2>
- <table>
- <tr>
- <td>
- <%= redis_get_value_as_array(key) %>
- </td>
- </tr>
- </table>
-<% end %>
82 lib/resque/server/views/layout.rb
View
@@ -0,0 +1,82 @@
+module Resque
+ module Views
+ class Layout < Mustache
+ include Server::Helpers
+
+ attr_reader :params, :request
+
+ def subtabs
+ []
+ end
+
+ def tabs
+ super.map do |tab_name|
+ { :tab => tab(tab_name) }
+ end
+ end
+
+ def custom_namespace?
+ namespace != :resque
+ end
+
+ def namespace
+ Resque.redis.namespace
+ end
+
+ def version
+ Resque::Version
+ end
+
+ def redis_server
+ Resque.redis.server
+ end
+
+ def resque
+ Resque
+ end
+
+ def any_subtabs?
+ keyed_subtabs.any?
+ end
+
+ def keyed_subtabs
+ Array(subtabs).map do |subtab|
+ { :subtab => subtab, :class => class_for_subtab(subtab) }
+ end
+ end
+
+ def class_for_subtab(subtab)
+ class_if_current "#{current_section}/#{subtab}"
+ end
+
+ def reset_css
+ css :reset
+ end
+
+ def style_css
+ css :style
+ end
+
+ def jquery_js
+ js "jquery-1.3.2.min"
+ end
+
+ def relatize_js
+ js "jquery.relatize_date"
+ end
+
+ def ranger_js
+ js :ranger
+ end
+
+ def css(name)
+ '<link href="' + u(name) +
+ '.css" media="screen" rel="stylesheet" type="text/css">'
+ end
+
+ def js(name)
+ '<script src="' + u(name) + '.js" type="text/javascript"></script>'
+ end
+ end
+ end
+end
10 lib/resque/server/views/next_more.erb
View
@@ -1,10 +0,0 @@
-<%if start - 20 >= 0 || start + 20 <= size%>
-<p class='pagination'>
- <% if start - 20 >= 0 %>
- <a href="<%= current_page %>?start=<%= start - 20 %>" class='less'>&laquo; less</a>
- <% end %>
- <% if start + 20 <= size %>
- <a href="<%= current_page %>?start=<%= start + 20 %>" class='more'>more &raquo;</a>
- <% end %>
-</p>
-<%end%>
4 lib/resque/server/views/overview.erb
View
@@ -1,4 +1,4 @@
-<%= partial :queues %>
+<%= erb_partial :queues %>
<hr />
-<%= partial :working %>
+<%= erb_partial :working %>
<%= poll %>
49 lib/resque/server/views/queues.erb
View
@@ -1,49 +0,0 @@
-<% @subtabs = resque.queues unless partial? %>
-
-<% if queue = params[:id] %>
-
- <h1>Pending jobs on <span class='hl'><%= queue %></span></h1>
- <form method="POST" action="<%=u "/queues/#{queue}/remove" %>" class='remove-queue'>
- <input type='submit' name='' value='Remove Queue' />
- </form>
- <p class='sub'>Showing <%= start = params[:start].to_i %> to <%= start + 20 %> of <b><%=size = resque.size(queue)%></b> jobs</p>
- <table class='jobs'>
- <tr>
- <th>Class</th>
- <th>Args</th>
- </tr>
- <% for job in (jobs = resque.peek(queue, start, 20)) %>
- <tr>
- <td class='class'><%= job['class'] %></td>
- <td class='args'><%=h job['args'].inspect %></td>
- </tr>
- <% end %>
- <% if jobs.empty? %>
- <tr>
- <td class='no-data' colspan='2'>There are no pending jobs in this queue</td>
- </tr>
- <% end %>
- </table>
- <%= partial :next_more, :start => start, :size => size %>
-<% else %>
-
- <h1 class='wi'>Queues</h1>
- <p class='intro'>The list below contains all the registered queues with the number of jobs currently in the queue. Select a queue from above to view all jobs currently pending on the queue.</p>
- <table class='queues'>
- <tr>
- <th>Name</th>
- <th>Jobs</th>
- </tr>
- <% for queue in resque.queues.sort_by { |q| q.to_s } %>
- <tr>
- <td class='queue'><a class="queue" href="<%= url "queues/#{queue}" %>"><%= queue %></a></td>
- <td class='size'><%= resque.size queue %></td>
- </tr>
- <% end %>
- <tr class="<%= Resque::Failure.count.zero? ? "failed" : "failure" %>">
- <td class='queue failed'><a class="queue" href="<%= url :failed %>">failed</a></td>
- <td class='size'><%= Resque::Failure.count %></td>
- </tr>
- </table>
-
-<% end %>
69 lib/resque/server/views/queues.rb
View
@@ -0,0 +1,69 @@
+module Resque
+ module Views
+ class Queues < Layout
+ def subtabs
+ Resque.queues
+ end
+
+ def queues?
+ !queue?
+ end
+
+ def queues
+ Resque.queues.sort_by { |q| q.to_s }.map do |queue|
+ { :queue => queue }
+ end
+ end
+
+ def queue?
+ queue && { :queue => queue }
+ end
+
+ def queue
+ params[:id]
+ end
+
+ def queue_url
+ u "queues/#{self[:queue]}"
+ end
+
+ def remove_queue_url
+ u "/queues/#{queue}"
+ end
+
+ def start
+ params[:start].to_i
+ end
+
+ def end
+ start + 20
+ end
+
+ def size
+ Resque.size(queue || self[:queue])
+ end
+
+ def jobs
+ Resque.peek(queue, start, 20).map do |job|
+ job.merge('args' => job['args'].inspect)
+ end
+ end
+
+ def no_jobs
+ jobs.empty?
+ end
+
+ def failure_class
+ failed_count.zero? ? :failed : :failure
+ end
+
+ def failed_count
+ Resque::Failure.count
+ end
+
+ def failed_url
+ url :failed
+ end
+ end
+ end
+end
62 lib/resque/server/views/stats.erb
View
@@ -1,62 +0,0 @@
-<% @subtabs = %w( resque redis keys ) %>
-
-<% if params[:key] %>
-
-<%= partial resque.redis.type(params[:key]).eql?("string") ? :key_string : :key_sets %>
-
-<% elsif params[:id] == "resque" %>
-
- <h1><%= resque %></h1>
- <table class='stats'>
- <% for key, value in resque.info.to_a.sort_by { |i| i[0].to_s } %>
- <tr>
- <th>
- <%= key %>
- </th>
- <td>
- <%= value %>
- </td>
- </tr>
- <% end %>
- </table>
-
-<% elsif params[:id] == 'redis' %>
-
- <h1><%= resque.redis.server %></h1>
- <table class='stats'>
- <% for key, value in resque.redis.info.to_a.sort_by { |i| i[0].to_s } %>
- <tr>
- <th>
- <%= key %>
- </th>
- <td>
- <%= value %>
- </td>
- </tr>
- <% end %>
- </table>
-
-<% elsif params[:id] == 'keys' %>
-
- <h1>Keys owned by <%= resque %></h1>
- <p class='sub'>(All keys are actually prefixed with "resque:")</p>
- <table class='stats'>
- <tr>
- <th>key</th>
- <th>type</th>
- <th>size</th>
- </tr>
- <% for key in resque.keys.sort %>
- <tr>
- <th>
- <a href="<%=u "/stats/keys/#{key}" %>"><%= key %></a>
- </th>
- <td><%= resque.redis.type key %></td>
- <td><%= redis_get_size key %></td>
- </tr>
- <% end %>
- </table>
-
-<% else %>
-
-<% end %>
134 lib/resque/server/views/stats.rb
View
@@ -0,0 +1,134 @@
+module Resque
+ module Views
+ class Stats < Layout
+ def subtabs
+ %w( resque redis keys )
+ end
+
+ def redis_server
+ Resque.redis.server
+ end
+
+ def key_page?
+ !!key
+ end
+
+ def set_key_page?
+ key && SetKeyInfo.new(key, params, request)
+ end
+
+ def key
+ params[:key]
+ end
+
+ def key_type(key = key)
+ resque.redis.type(key)
+ end
+
+ def key_size(key = key)
+ redis_get_size(key)
+ end
+
+ def key_value_as_array(key = key)
+ redis_get_value_as_array(key)
+ end
+
+ def partial(name)
+ respond_to?(name) ? send(name) : super
+ end
+
+ def key_string_or_sets
+ type = Resque.redis.type(params[:key]) == "string"
+ partial(type ? :key_string : :key_sets)
+ end
+
+ def keys_page?
+ params[:id] == "keys"
+ end
+
+ def keys
+ Resque.keys.sort.map do |key|
+ hash = {}
+ hash[:name] = key
+ hash[:href] = u("/stats/keys/#{key}")
+ hash[:type] = key_type(key)
+ hash[:size] = key_size(key)
+ hash
+ end
+ end
+
+ def resque_page?
+ ResqueInfo.new if params[:id] == "resque"
+ end
+
+ def redis_page?
+ RedisInfo.new if params[:id] == "redis"
+ end
+
+ class ResqueInfo
+ def stats
+ Resque.info.to_a.sort_by { |i| i[0].to_s }.map do |key, value|
+ { :key => key, :value => value }
+ end
+ end
+ end
+
+ class RedisInfo
+ def stats
+ Resque.redis.info.to_a.sort_by { |i| i[0].to_s }.map do |key, value|
+ { :key => key, :value => value }
+ end
+ end
+ end
+
+ class SetKeyInfo
+ include Server::Helpers
+
+ attr_reader :key, :params, :request
+ def initialize(key, params, request)
+ @key = key
+ @params = params
+ @request = request
+ end
+
+ def start
+ params[:start].to_i
+ end
+
+ def end
+ start + 20
+ end
+
+ def size
+ redis_get_size(key)
+ end
+
+ def pagination?
+ less_page? || more_page?
+ end
+
+ def less_page?
+ start - 20 >= 0
+ end
+
+ def more_page?
+ start + 20 <= size
+ end
+
+ def start_less
+ start - 20
+ end
+
+ def start_more
+ start + 20
+ end
+
+ def key_as_array
+ redis_get_value_as_array(key, start).map do |item|
+ { :row => item }
+ end
+ end
+ end
+ end
+ end
+end
47 lib/resque/server/views/worker_list.rb
View
@@ -0,0 +1,47 @@
+module Resque
+ module Views
+ class WorkerList < Layout
+ def state_icon
+ state = self[:state]
+ %(<img src="#{u(state)}.png" alt="#{state}" title="#{state}">)
+ end
+
+ # If we're not looking at a single worker, we're looking at all
+ # fo them.
+ def all_workers?
+ !params[:id]
+ end
+
+ # Host where the current worker lives.
+ def worker_host
+ worker_parts[0]
+ end
+
+ # PID of the current worker.
+ def worker_pid
+ worker_parts[1]
+ end
+
+ # Queues the current worker is concerned with.
+ def worker_queues
+ worker_parts[2..-1]
+ end
+
+ # The current worker's name split into three parts:
+ # [ host, pid, queues ]
+ def worker_parts
+ self[:to_s].split(':')
+ end
+
+ # Worker URL of the current worker
+ def worker_url
+ u "/workers/#{self[:to_s]}"
+ end
+
+ # Working URL of the current working
+ def working_url
+ u "/working/#{self[:to_s]}"
+ end
+ end
+ end
+end
78 lib/resque/server/views/workers.erb
View
@@ -1,78 +0,0 @@
-<% if params[:id] && worker = Resque::Worker.find(params[:id]) %>
-
- <h1>Worker <%= worker %></h1>
- <table class='workers'>
- <tr>
- <th>&nbsp;</th>
- <th>Host</th>
- <th>Pid</th>
- <th>Started</th>
- <th>Queues</th>
- <th>Processed</th>
- <th>Failed</th>
- <th>Processing</th>
- </tr>
- <tr>
- <td class='icon'><img src="<%=u state = worker.state %>.png" alt="<%= state %>" title="<%= state %>"></td>
-
- <% host, pid, queues = worker.to_s.split(':') %>
- <td><%= host %></td>
- <td><%= pid %></td>
- <td><span class="time"><%= worker.started %></span></td>
- <td class='queues'><%= queues.split(',').map { |q| '<a class="queue-tag" href="' + u("/queues/#{q}") + '">' + q + '</a>'}.join('') %></td>
- <td><%= worker.processed %></td>
- <td><%= worker.failed %></td>
- <td class='process'>
- <% data = worker.processing || {} %>
- <% if data['queue'] %>
- <code><%= data['payload']['class'] %></code>
- <small><a class="queue time" href="<%=u "/working/#{worker}" %>"><%= data['run_at'] %></a></small>
- <% else %>
- <span class='waiting'>Waiting for a job...</span>
- <% end %>
- </td>
- </tr>
- </table>
-
-<% elsif params[:id] %>
-
-<h1>Worker doesn't exist</h1>
-
-<% else %>
-
- <h1 class='wi'><%= resque.workers.size %> Workers</h1>
- <p class='intro'>The workers listed below are all registered as active on your system.</p>
- <table class='workers'>
- <tr>
- <th>&nbsp;</th>
- <th>Where</th>
- <th>Queues</th>
- <th>Processing</th>
- </tr>
- <% for worker in (workers = resque.workers.sort_by { |w| w.to_s }) %>
- <tr class="<%=state = worker.state%>">
- <td class='icon'><img src="<%=u state %>.png" alt="<%= state %>" title="<%= state %>"></td>
-
- <% host, pid, queues = worker.to_s.split(':') %>
- <td class='where'><a href="<%=u "workers/#{worker}"%>"><%= host %>:<%= pid %></a></td>
- <td class='queues'><%= queues.split(',').map { |q| '<a class="queue-tag" href="' + u("/queues/#{q}") + '">' + q + '</a>'}.join('') %></td>
-
- <td class='process'>
- <% data = worker.processing || {} %>
- <% if data['queue'] %>
- <code><%= data['payload']['class'] %></code>
- <small><a class="queue time" href="<%=u "/working/#{worker}" %>"><%= data['run_at'] %></a></small>
- <% else %>
- <span class='waiting'>Waiting for a job...</span>
- <% end %>
- </td>
- </tr>
- <% end %>
- <% if workers.empty? %>
- <tr>
- <td colspan='4' class='no-data'>There are no registered workers</td>
- </tr>
- <% end %>
- </table>
- <%=poll%>
-<% end %>
35 lib/resque/server/views/workers.rb
View
@@ -0,0 +1,35 @@
+module Resque
+ module Views
+ class Workers < WorkerList
+ def worker?
+ if id = params[:id]
+ Resque::Worker.find(id)
+ end
+ end
+
+ def worker_not_found?
+ params[:id] && !Resque::Worker.find(id)
+ end
+
+ def workers
+ Resque.workers.sort_by { |w| w.to_s }
+ end
+
+ def linked_queues
+ links = self[:queues].map do |q|
+ %(<a class="queue-tag" href="#{u("/queues/#{q}")}">#{q}</a>)
+ end
+
+ links.join('')
+ end
+
+ def no_workers?
+ workers.empty?
+ end
+
+ def not_processing
+ !self[:processing]
+ end
+ end
+ end
+end
51 lib/resque/server/views/working.rb
View
@@ -0,0 +1,51 @@
+module Resque
+ module Views
+ class Working < WorkerList
+ # If we're only looking at a single worker, return it as the
+ # context.
+ def single_worker?
+ id = params[:id]
+ if id && (worker = Resque::Worker.find(id)) && worker.job
+ worker
+ end
+ end
+
+ # A sorted array of workers currently working.
+ def working
+ Resque.working.
+ sort_by { |w| w.job['run_at'] ? w.job['run_at'] : '' }.
+ reject { |w| w.idle? }
+ end
+
+ # Is no one working?
+ def none_working?
+ working.empty?
+ end
+
+ # Does this context have a job?
+ def no_job
+ !self[:job]
+ end
+
+ # The number of workers currently working.
+ def workers_working
+ Resque.working.size
+ end
+
+ # The number of workers total.
+ def workers_total
+ Resque.workers.size
+ end
+
+ # TODO: Mustache method_missing this guy
+ def queue
+ self[:queue]
+ end
+
+ # URL of the current job's queue
+ def queue_url
+ u "/queues/#{queue}"
+ end
+ end
+ end
+end

Showing you all comments on commits in this comparison.

Michael Dwan

Awesome! Resque-web will be a great sample mustache app.

Something went wrong with that request. Please try again.