lib/qless/server.rb in qless-0.9.1 vs lib/qless/server.rb in qless-0.9.2
- old
+ new
@@ -7,25 +7,25 @@
class Server < Sinatra::Base
# Path-y-ness
dir = File.dirname(File.expand_path(__FILE__))
set :views , "#{dir}/server/views"
set :public_folder, "#{dir}/server/static"
-
+
# For debugging purposes at least, I want this
set :reload_templates, true
-
+
# I'm not sure what this option is -- I'll look it up later
# set :static, true
-
+
def self.client
@client ||= Qless::Client.new
end
def self.client=(client)
@client = client
end
-
+
helpers do
include Rack::Utils
def url_path(*path_parts)
[ path_prefix, path_parts ].join("/").squeeze('/')
@@ -33,53 +33,92 @@
alias_method :u, :url_path
def path_prefix
request.env['SCRIPT_NAME']
end
-
+
+ def url_with_modified_query
+ url = URI(request.url)
+ existing_query = Rack::Utils.parse_query(url.query)
+ url.query = Rack::Utils.build_query(yield existing_query)
+ url.to_s
+ end
+
+ def page_url(offset)
+ url_with_modified_query do |query|
+ query.merge('page' => current_page + offset)
+ end
+ end
+
+ def next_page_url
+ page_url 1
+ end
+
+ def prev_page_url
+ page_url -1
+ end
+
+ def current_page
+ @current_page ||= begin
+ Integer(params[:page])
+ rescue
+ 1
+ end
+ end
+
+ PAGE_SIZE = 25
+ def pagination_values
+ start = (current_page - 1) * PAGE_SIZE
+ [start, start + PAGE_SIZE]
+ end
+
+ def paginated(qless_object, method, *args)
+ qless_object.send(method, *(args + pagination_values))
+ end
+
def tabs
return [
{:name => 'Queues' , :path => '/queues' },
{:name => 'Workers' , :path => '/workers' },
{:name => 'Track' , :path => '/track' },
{:name => 'Failed' , :path => '/failed' },
{:name => 'Config' , :path => '/config' },
{:name => 'About' , :path => '/about' }
]
end
-
+
def application_name
return Server.client.config['application']
end
-
+
def queues
return Server.client.queues.counts
end
-
+
def tracked
return Server.client.jobs.tracked
end
-
+
def workers
return Server.client.workers.counts
end
-
+
def failed
return Server.client.jobs.failed
end
-
+
# Return the supplied object back as JSON
def json(obj)
content_type :json
obj.to_json
end
-
+
# Make the id acceptable as an id / att in HTML
def sanitize_attr(attr)
return attr.gsub(/[^a-zA-Z\:\_]/, '-')
end
-
+
# What are the top tags? Since it might go on, say, every
# page, then we should probably be caching it
def top_tags
@top_tags ||= {
:top => Server.client.tags,
@@ -91,110 +130,107 @@
:fetched => Time.now
}
end
@top_tags[:top]
end
-
+
def strftime(t)
# From http://stackoverflow.com/questions/195740/how-do-you-do-relative-time-in-rails
diff_seconds = Time.now - t
case diff_seconds
when 0 .. 59
"#{diff_seconds.to_i} seconds ago"
when 60 ... 3600
"#{(diff_seconds/60).to_i} minutes ago"
when 3600 ... 3600*24
"#{(diff_seconds/3600).to_i} hours ago"
- when (3600*24) ... (3600*24*30)
+ when (3600*24) ... (3600*24*30)
"#{(diff_seconds/(3600*24)).to_i} days ago"
else
t.strftime('%b %e, %Y %H:%M:%S %Z (%z)')
end
end
end
-
+
get '/?' do
erb :overview, :layout => true, :locals => { :title => "Overview" }
end
-
+
# Returns a JSON blob with the job counts for various queues
get '/queues.json' do
json(Server.client.queues.counts)
end
-
+
get '/queues/?' do
erb :queues, :layout => true, :locals => {
:title => 'Queues'
}
end
-
+
# Return the job counts for a specific queue
get '/queues/:name.json' do
json(Server.client.queues[params[:name]].counts)
end
-
+
+ filtered_tabs = %w[ running scheduled stalled depends recurring ].to_set
get '/queues/:name/?:tab?' do
queue = Server.client.queues[params[:name]]
- tab = params.fetch('tab', 'stats')
- jobs = []
- case tab
- when 'running'
- jobs = queue.jobs.running
- when 'scheduled'
- jobs = queue.jobs.scheduled
- when 'stalled'
- jobs = queue.jobs.stalled
- when 'depends'
- jobs = queue.jobs.depends
- when 'recurring'
- jobs = queue.jobs.recurring
+ tab = params.fetch('tab', 'stats')
+
+ jobs = if tab == 'waiting'
+ queue.peek(20)
+ elsif filtered_tabs.include?(tab)
+ paginated(queue.jobs, tab).map { |jid| Server.client.jobs[jid] }
+ else
+ []
end
- jobs = jobs.map { |jid| Server.client.jobs[jid] }
- if tab == 'waiting'
- jobs = queue.peek(20)
- end
+
erb :queue, :layout => true, :locals => {
:title => "Queue #{params[:name]}",
:tab => tab,
:jobs => jobs,
:queue => Server.client.queues[params[:name]].counts,
:stats => queue.stats
}
end
-
+
+ get '/failed.json' do
+ json(Server.client.jobs.failed)
+ end
+
get '/failed/?' do
# qless-core doesn't provide functionality this way, so we'll
# do it ourselves. I'm not sure if this is how the core library
# should behave or not.
erb :failed, :layout => true, :locals => {
:title => 'Failed',
:failed => Server.client.jobs.failed.keys.map { |t| Server.client.jobs.failed(t).tap { |f| f['type'] = t } }
}
end
-
+
get '/failed/:type/?' do
erb :failed_type, :layout => true, :locals => {
:title => 'Failed | ' + params[:type],
:type => params[:type],
- :failed => Server.client.jobs.failed(params[:type])
+ :failed => paginated(Server.client.jobs, :failed, params[:type])
}
end
-
+
get '/track/?' do
erb :track, :layout => true, :locals => {
:title => 'Track'
}
end
-
+
get '/jobs/:jid' do
erb :job, :layout => true, :locals => {
:title => "Job | #{params[:jid]}",
:jid => params[:jid],
:job => Server.client.jobs[params[:jid]]
}
end
-
+
get '/workers/?' do
erb :workers, :layout => true, :locals => {
:title => 'Workers'
}
end
@@ -207,40 +243,34 @@
w['stalled'] = w['stalled'].map { |j| Server.client.jobs[j] }
w['name'] = params[:worker]
}
}
end
-
+
get '/tag/?' do
- jobs = Server.client.jobs.tagged(params[:tag])
+ jobs = paginated(Server.client.jobs, :tagged, params[:tag])
erb :tag, :layout => true, :locals => {
:title => "Tag | #{params[:tag]}",
:tag => params[:tag],
:jobs => jobs['jobs'].map { |jid| Server.client.jobs[jid] },
:total => jobs['total']
}
end
-
+
get '/config/?' do
erb :config, :layout => true, :locals => {
:title => 'Config',
:options => Server.client.config.all
}
end
-
+
get '/about/?' do
erb :about, :layout => true, :locals => {
:title => 'About'
}
end
-
-
-
-
-
-
-
+
# These are the bits where we accept AJAX requests
post "/track/?" do
# Expects a JSON-encoded hash with a job id, and optionally some tags
data = JSON.parse(request.body.read)
job = Server.client.jobs[data["id"]]
@@ -257,21 +287,21 @@
else
redirect to(request.referrer)
end
end
end
-
+
post "/untrack/?" do
# Expects a JSON-encoded array of job ids to stop tracking
jobs = JSON.parse(request.body.read).map { |jid| Server.client.jobs[jid] }.select { |j| not j.nil? }
# Go ahead and cancel all the jobs!
jobs.each do |job|
job.untrack()
end
return json({ :untracked => jobs.map { |job| job.jid } })
end
-
+
post "/priority/?" do
# Expects a JSON-encoded dictionary of jid => priority
response = Hash.new
r = JSON.parse(request.body.read)
r.each_pair do |jid, priority|
@@ -282,11 +312,11 @@
response[jid] = 'failed'
end
end
return json(response)
end
-
+
post "/tag/?" do
# Expects a JSON-encoded dictionary of jid => [tag, tag, tag]
response = Hash.new
JSON.parse(request.body.read).each_pair do |jid, tags|
begin
@@ -296,11 +326,11 @@
response[jid] = 'failed'
end
end
return json(response)
end
-
+
post "/untag/?" do
# Expects a JSON-encoded dictionary of jid => [tag, tag, tag]
response = Hash.new
JSON.parse(request.body.read).each_pair do |jid, tags|
begin
@@ -310,11 +340,11 @@
response[jid] = 'failed'
end
end
return json(response)
end
-
+
post "/move/?" do
# Expects a JSON-encoded hash of id: jid, and queue: queue_name
data = JSON.parse(request.body.read)
if data["id"].nil? or data["queue"].nil?
halt 400, "Need id and queue arguments"
@@ -326,11 +356,11 @@
job.move(data["queue"])
return json({ :id => data["id"], :queue => data["queue"]})
end
end
end
-
+
post "/undepend/?" do
# Expects a JSON-encoded hash of id: jid, and queue: queue_name
data = JSON.parse(request.body.read)
if data["id"].nil?
halt 400, "Need id"
@@ -342,11 +372,11 @@
job.undepend(data['dependency'])
return json({:id => data["id"]})
end
end
end
-
+
post "/retry/?" do
# Expects a JSON-encoded hash of id: jid, and queue: queue_name
data = JSON.parse(request.body.read)
if data["id"].nil?
halt 400, "Need id"
@@ -359,11 +389,11 @@
job.move(queue)
return json({ :id => data["id"], :queue => queue})
end
end
end
-
+
# Retry all the failures of a particular type
post "/retryall/?" do
# Expects a JSON-encoded hash of type: failure-type
data = JSON.parse(request.body.read)
if data["type"].nil?
@@ -374,26 +404,26 @@
job.move(queue)
{ :id => job.jid, :queue => queue}
end)
end
end
-
+
post "/cancel/?" do
# Expects a JSON-encoded array of job ids to cancel
jobs = JSON.parse(request.body.read).map { |jid| Server.client.jobs[jid] }.select { |j| not j.nil? }
# Go ahead and cancel all the jobs!
jobs.each do |job|
job.cancel()
end
-
+
if request.xhr?
return json({ :canceled => jobs.map { |job| job.jid } })
else
redirect to(request.referrer)
end
end
-
+
post "/cancelall/?" do
# Expects a JSON-encoded hash of type: failure-type
data = JSON.parse(request.body.read)
if data["type"].nil?
halt 400, "Neet type"
@@ -402,10 +432,10 @@
job.cancel()
{ :id => job.jid }
end)
end
end
-
+
# start the server if ruby file executed directly
run! if app_file == $0
end
end