Skip to content

Commit e8f5a62

Browse files
authored
Merge pull request sidekiq-cron#211 from Akhilesh05/added-jid-history
Added jid history, just like Sidekiq Enterprise
2 parents 5f86d74 + 83b34ec commit e8f5a62

10 files changed

Lines changed: 261 additions & 27 deletions

File tree

lib/sidekiq/cron/job.rb

Lines changed: 56 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -57,21 +57,23 @@ def enque! time = Time.now.utc
5757
nil
5858
end
5959

60-
if klass_const
61-
if defined?(ActiveJob::Base) && klass_const < ActiveJob::Base
62-
enqueue_active_job(klass_const)
63-
else
64-
enqueue_sidekiq_worker(klass_const)
65-
end
66-
else
67-
if @active_job
68-
Sidekiq::Client.push(active_job_message)
60+
jid =
61+
if klass_const
62+
if defined?(ActiveJob::Base) && klass_const < ActiveJob::Base
63+
enqueue_active_job(klass_const).try :provider_job_id
64+
else
65+
enqueue_sidekiq_worker(klass_const)
66+
end
6967
else
70-
Sidekiq::Client.push(sidekiq_worker_message)
68+
if @active_job
69+
Sidekiq::Client.push(active_job_message)
70+
else
71+
Sidekiq::Client.push(sidekiq_worker_message)
72+
end
7173
end
72-
end
7374

7475
save_last_enqueue_time
76+
add_jid_history jid
7577
logger.debug { "enqueued #{@name}: #{@message}" }
7678
end
7779

@@ -83,14 +85,10 @@ def is_active_job?
8385

8486
def enqueue_active_job(klass_const)
8587
klass_const.set(queue: @queue).perform_later(*@args)
86-
87-
true
8888
end
8989

9090
def enqueue_sidekiq_worker(klass_const)
9191
klass_const.set(queue: queue_name_with_prefix).perform_async(*@args)
92-
93-
true
9492
end
9593

9694
# siodekiq worker message
@@ -350,6 +348,12 @@ def disabled?
350348
!enabled?
351349
end
352350

351+
def pretty_message
352+
JSON.pretty_generate Sidekiq.load_json(message)
353+
rescue JSON::ParserError
354+
message
355+
end
356+
353357
def status_from_redis
354358
out = "enabled"
355359
if fetch_missing_args
@@ -371,6 +375,18 @@ def last_enqueue_time_from_redis
371375
out
372376
end
373377

378+
def jid_history_from_redis
379+
out =
380+
Sidekiq.redis do |conn|
381+
conn.lrange(jid_history_key, 0, -1) rescue nil
382+
end
383+
384+
# returns nil if out nil
385+
out && out.map do |jid_history_raw|
386+
Sidekiq.load_json jid_history_raw
387+
end
388+
end
389+
374390
#export job data to hash
375391
def to_hash
376392
{
@@ -457,6 +473,20 @@ def save_last_enqueue_time
457473
end
458474
end
459475

476+
def add_jid_history(jid)
477+
jid_history = {
478+
jid: jid,
479+
enqueued: @last_enqueue_time
480+
}
481+
@history_size ||= (Sidekiq.options[:cron_history_size] || 10).to_i - 1
482+
Sidekiq.redis do |conn|
483+
conn.lpush jid_history_key,
484+
Sidekiq.dump_json(jid_history)
485+
# keep only last 10 entries in a fifo manner
486+
conn.ltrim jid_history_key, 0, @history_size
487+
end
488+
end
489+
460490
# remove job from cron jobs by name
461491
# input:
462492
# first arg: name (string) - name of job (must be same - case sensitive)
@@ -468,6 +498,9 @@ def destroy
468498
#delete runned timestamps
469499
conn.del job_enqueued_key
470500

501+
# delete jid_history
502+
conn.del jid_history_key
503+
471504
#delete main job
472505
conn.del redis_key
473506
end
@@ -586,12 +619,20 @@ def self.job_enqueued_key name
586619
"cron_job:#{name}:enqueued"
587620
end
588621

622+
def self.jid_history_key name
623+
"cron_job:#{name}:jid_history"
624+
end
625+
589626
# Redis key for storing one cron job run times
590627
# (when poller added job to queue)
591628
def job_enqueued_key
592629
self.class.job_enqueued_key @name
593630
end
594631

632+
def jid_history_key
633+
self.class.jid_history_key @name
634+
end
635+
595636
# Give Hash
596637
# returns array for using it for redis.hmset
597638
def hash_to_redis hash

lib/sidekiq/cron/locales/en.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ en:
1616
'Last enque': Last enqueued
1717
disabled: disabled
1818
enabled: enabled
19+
NoHistoryWereFound: No history were found

lib/sidekiq/cron/views/cron.erb

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,9 @@
4141
<tr>
4242
<td style="<%= style %>"><%= t job.status %></td>
4343
<td style="<%= style %>">
44-
<b><%= job.name %></b>
44+
<a href="<%= root_path %>cron/<%= CGI.escape(job.name).gsub('+', '%20') %>">
45+
<b><%= job.name %></b>
46+
</a>
4547
<hr style="margin:3px;border:0;">
4648
<small>
4749
<% if job.message and job.message.to_s.size > 100 %>

lib/sidekiq/cron/views/cron.slim

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ header.row
3434
tr
3535
td[style="#{style}"]= job.status
3636
td[style="#{style}"]
37-
b job.name
37+
a href="#{root_path}cron/#{CGI.escape(job.name).gsub('+', '%20')}"
38+
b = job.name
3839
hr style="margin:3px;border:0;"
3940
small
4041
- if job.message and job.message.to_s.size > 100
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
<header class="row">
2+
<div class="span col-sm-5 pull-left">
3+
<h3>
4+
<%= "#{t('Cron')} #{t('Job')}" %>
5+
<small><%= @job.name %></small>
6+
</h3>
7+
</div>
8+
<div class="span col-sm-7 pull-right" style="margin-top: 20px; margin-bottom: 10px;">
9+
<% cron_job_path = "#{root_path}cron/#{CGI.escape(@job.name).gsub('+', '%20')}" %>
10+
<form action="<%= cron_job_path %>/enque?redirect=<%= cron_job_path %>" class="pull-right" method="post">
11+
<%= csrf_tag if respond_to?(:csrf_tag) %>
12+
<input class="btn btn-small pull-left" name="enque" type="submit" value="<%= t('EnqueueNow') %>" />
13+
</form>
14+
<% if @job.status == 'enabled' %>
15+
<form action="<%= cron_job_path %>/disable?redirect=<%= cron_job_path %>" class="pull-right" method="post">
16+
<%= csrf_tag if respond_to?(:csrf_tag) %>
17+
<input class="btn btn-small pull-left" name="disable" type="submit" value="<%= t('Disable') %>" />
18+
</form>
19+
<% else %>
20+
<form action="<%= cron_job_path %>/enable?redirect=<%= cron_job_path %>" class="pull-right" method="post">
21+
<%= csrf_tag if respond_to?(:csrf_tag) %>
22+
<input class="btn btn-small pull-left" name="enable" type="submit" value="<%= t('Enable') %>" />
23+
</form>
24+
<form action="<%= cron_job_path %>/delete" class="pull-right" method="post">
25+
<%= csrf_tag if respond_to?(:csrf_tag) %>
26+
<input class="btn btn-danger btn-small" data-confirm="<%= t('AreYouSureDeleteCronJob', :job => @job.name) %>" name="delete" type="submit" value="<%= t('Delete') %>" />
27+
</form>
28+
<% end %>
29+
</div>
30+
</header>
31+
32+
<table class="table table-bordered table-striped">
33+
<tbody>
34+
<tr>
35+
<th><%= t 'Status' %></th>
36+
<td><%= @job.status %></td>
37+
</tr>
38+
<tr>
39+
<th><%= t 'Name' %></th>
40+
<td><%= @job.name %></td>
41+
</tr>
42+
<tr>
43+
<th><%= t 'Message' %></th>
44+
<td><pre><%= @job.pretty_message %></pre></td>
45+
</tr>
46+
<tr>
47+
<th><%= t 'Cron' %></th>
48+
<td><%= @job.cron.gsub(" ", "&nbsp;") %></td>
49+
</tr>
50+
<tr>
51+
<th><%= t 'Last enque' %></th>
52+
<td><%= @job.last_enqueue_time ? relative_time(@job.last_enqueue_time) : "-" %></td>
53+
</tr>
54+
</tbody>
55+
</table>
56+
57+
<header class="row">
58+
<div class="col-sm-12">
59+
<h4>
60+
<%= t 'History' %>
61+
</h4>
62+
</div>
63+
</header>
64+
65+
<% if @job.jid_history_from_redis.size > 0 %>
66+
<table class="table table-hover table-bordered table-striped">
67+
<thead>
68+
<tr>
69+
<th><%= t 'Enqueued' %></th>
70+
<th><%= t 'JID' %></th>
71+
</tr>
72+
</thead>
73+
<tbody>
74+
<% @job.jid_history_from_redis.each do |jid_history| %>
75+
<tr>
76+
<td><%= jid_history['enqueued'] %></td>
77+
<td><%= jid_history['jid'] %></td>
78+
</tr>
79+
<% end %>
80+
</tbody>
81+
</table>
82+
<% else %>
83+
<div class='alert alert-success'><%= t 'NoHistoryWereFound' %></div>
84+
<% end %>
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
header.row
2+
.span.col-sm-5.pull-left
3+
h3
4+
= "#{t('Cron')} #{t('Job')}"
5+
small= @job.name
6+
.span.col-sm-7.pull-right style=("margin-top: 20px; margin-bottom: 10px;")
7+
- cron_job_path = "#{root_path}cron/#{CGI.escape(@job.name).gsub('+', '%20')}"
8+
form.pull-right action="#{cron_job_path}/enque?redirect=#{cron_job_path}" method="post"
9+
= csrf_tag if respond_to?(:csrf_tag)
10+
input.btn.btn-small.pull-left name="enque" type="submit" value="#{t('EnqueueNow')}"
11+
- if @job.status == 'enabled'
12+
form.pull-right action="#{cron_job_path}/disable?redirect=#{cron_job_path}" method="post"
13+
= csrf_tag if respond_to?(:csrf_tag)
14+
input.btn.btn-small.pull-left name="disable" type="submit" value="#{t('Disable')}"
15+
- else
16+
form.pull-right action="#{cron_job_path}/enable?redirect=#{cron_job_path}" method="post"
17+
= csrf_tag if respond_to?(:csrf_tag)
18+
input.btn.btn-small.pull-left name="enable" type="submit" value="#{t('Enable')}"
19+
form.pull-right action="#{cron_job_path}/delete" method="post"
20+
= csrf_tag if respond_to?(:csrf_tag)
21+
input.btn.btn-danger.btn-small data-confirm="#{t('AreYouSureDeleteCronJob' job =@job.name)}" name="delete" type="submit" value="#{t('Delete')}" /
22+
23+
table.table.table-bordered.table-striped
24+
tbody
25+
tr
26+
th= t 'Status'
27+
td= @job.status
28+
tr
29+
th= t 'Name'
30+
td= @job.name
31+
tr
32+
th= t 'Message'
33+
td
34+
pre= @job.pretty_message
35+
tr
36+
th= t 'Cron'
37+
td= @job.cron.gsub(" ", "&nbsp;")
38+
tr
39+
th= t 'Last enque'
40+
td= @job.last_enqueue_time ? relative_time(@job.last_enqueue_time) : "-"
41+
42+
header.row
43+
.col-sm-12
44+
h4= t 'History'
45+
46+
- if @job.jid_history_from_redis.size > 0
47+
table.table.table-hover.table-bordered.table-striped
48+
thead
49+
tr
50+
th= t 'Enqueued'
51+
th= t 'JID'
52+
tbody
53+
- @job.jid_history_from_redis.each do |jid_history|
54+
tr
55+
td= jid_history['enqueued']
56+
td= jid_history['jid']
57+
- else
58+
.alert.alert-success= t 'NoHistoryWereFound'

lib/sidekiq/cron/web_extension.rb

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,31 @@ def self.registered(app)
2020
end
2121
end
2222

23+
# display job detail + jid history
24+
app.get '/cron/:name' do
25+
view_path = File.join(File.expand_path("..", __FILE__), "views")
26+
27+
@job = Sidekiq::Cron::Job.find(route_params[:name])
28+
if @job.present?
29+
#if Slim renderer exists and sidekiq has layout.slim in views
30+
if defined?(Slim) && File.exists?(File.join(settings.views,"layout.slim"))
31+
render(:slim, File.read(File.join(view_path, "cron_show.slim")))
32+
else
33+
render(:erb, File.read(File.join(view_path, "cron_show.erb")))
34+
end
35+
else
36+
redirect "#{root_path}cron"
37+
end
38+
end
39+
2340
#enque cron job
2441
app.post '/cron/:name/enque' do
2542
if route_params[:name] === '__all__'
2643
Sidekiq::Cron::Job.all.each(&:enque!)
2744
elsif job = Sidekiq::Cron::Job.find(route_params[:name])
2845
job.enque!
2946
end
30-
redirect "#{root_path}cron"
47+
redirect params['redirect'] || "#{root_path}cron"
3148
end
3249

3350
#delete schedule
@@ -47,7 +64,7 @@ def self.registered(app)
4764
elsif job = Sidekiq::Cron::Job.find(route_params[:name])
4865
job.enable!
4966
end
50-
redirect "#{root_path}cron"
67+
redirect params['redirect'] || "#{root_path}cron"
5168
end
5269

5370
#disable job
@@ -57,7 +74,7 @@ def self.registered(app)
5774
elsif job = Sidekiq::Cron::Job.find(route_params[:name])
5875
job.disable!
5976
end
60-
redirect "#{root_path}cron"
77+
redirect params['redirect'] || "#{root_path}cron"
6178
end
6279

6380
end

test/test_helper.rb

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,13 @@ def perform args = {}
6666

6767
module ActiveJob
6868
class Base
69+
attr_accessor *%i[job_class provider_job_id queue_name arguments]
70+
71+
def initialize
72+
yield self if block_given?
73+
self.provider_job_id ||= SecureRandom.hex(12)
74+
end
75+
6976
def self.queue_name_prefix
7077
@queue_name_prefix
7178
end
@@ -80,12 +87,16 @@ def self.set(options)
8087
self
8188
end
8289

90+
def try(method, *args, &block)
91+
send method, *args, &block if respond_to? method
92+
end
93+
8394
def self.perform_later(*args)
84-
{
85-
"job_class" => self.class.name,
86-
"queue_name" => @queue,
87-
"args" => [*args],
88-
}
95+
new do |instance|
96+
instance.job_class = self.class.name
97+
instance.queue_name = @queue
98+
instance.arguments = [*args]
99+
end
89100
end
90101
end
91102
end

0 commit comments

Comments
 (0)