sidekiq-hierarchy 1.1.0 → 2.0.0
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +10 -4
- data/lib/sidekiq/hierarchy.rb +18 -19
- data/lib/sidekiq/hierarchy/faraday/middleware.rb +2 -2
- data/lib/sidekiq/hierarchy/http.rb +1 -1
- data/lib/sidekiq/hierarchy/job.rb +54 -2
- data/lib/sidekiq/hierarchy/rack/middleware.rb +4 -4
- data/lib/sidekiq/hierarchy/server/middleware.rb +2 -2
- data/lib/sidekiq/hierarchy/version.rb +1 -1
- data/lib/sidekiq/hierarchy/web.rb +4 -0
- data/lib/sidekiq/hierarchy/workflow.rb +15 -19
- data/web/views/_workflow_table.erb +2 -2
- data/web/views/_workflow_tree_node.erb +5 -3
- data/web/views/status.erb +14 -8
- data/web/views/workflow.erb +2 -0
- metadata +57 -55
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7da49b3d427ff6aad77da49fbf6aedcbaf9ba70b
|
4
|
+
data.tar.gz: 9ac4dcc0972bba86b7d251ef73be6297fc19627b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 61442fd3a766b589dcaed9570320e7aebddbc7b695ad1ef7e65dba6b0f976c0441b752dd19104e76aa99c646445dc23b0482954a5ac0ee692e438bfb185cb9ce
|
7
|
+
data.tar.gz: 6f7b1463ba5e4d27fcff502a7136b7ddec1c8b82e4605fd8767f9bea681fe3b9ab4069f6224c313a5c93ad963f0b1af06ef063a315af39481ff562365cef2a28
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,17 @@
|
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
3
|
This project adheres to [Semantic Versioning](http://semver.org/).
|
4
4
|
|
5
|
+
## [2.0.0] - 2015-12-04
|
6
|
+
### Changed
|
7
|
+
- HTTP headers renamed to make roles more clear
|
8
|
+
- Thread locals renamed to make collisions less likely
|
9
|
+
|
10
|
+
### Added
|
11
|
+
- Track workflow timings directly to avoid iteration
|
12
|
+
- Record per-subtree job counts and finished job counts
|
13
|
+
- Add subtree iteration
|
14
|
+
|
15
|
+
|
5
16
|
## [1.1.0] - 2015-12-04
|
6
17
|
### Changed
|
7
18
|
- Use Sinatra template helpers to get template caching for views
|
data/README.md
CHANGED
@@ -107,11 +107,17 @@ Some examples to try, given a root `JID`:
|
|
107
107
|
=> [2015-11-11 15:00:42 -0800, 2015-11-11 15:00:42 -0800, 2015-11-11 15:01:32 -0800]
|
108
108
|
```
|
109
109
|
```ruby
|
110
|
+
> workflow.job_count # stored value, no iteration necessary
|
111
|
+
=> 33
|
112
|
+
|
110
113
|
> workflow.jobs.count # lazily eval'd
|
111
114
|
=> 33
|
112
115
|
|
113
116
|
> workflow.jobs.map(&:jid)
|
114
117
|
=> ["11c3ec3df251ebb646f910d7", "f003db430a0eae99d72f1b7a", "bc2cf8f3de3b87f9a4c3c10e", ...]
|
118
|
+
|
119
|
+
> workflow.finished_job_count
|
120
|
+
=> 33
|
115
121
|
```
|
116
122
|
```ruby
|
117
123
|
> root_job = workflow.root
|
@@ -176,7 +182,7 @@ Explore the classes to learn more you can access, including:
|
|
176
182
|
- timestamps for all status changes (`#enqueued_at`, `#run_at`, etc.)
|
177
183
|
- tree exploration (`#root`, `#parent`, `#children`, `#leaf?`, etc.)
|
178
184
|
- lazy enumerators over jobs and workflows (`Workflow#jobs`, `WorkflowSet#each`)
|
179
|
-
- current workflow and job
|
185
|
+
- current workflow and job context (`Sidekiq::Hierarchy.current_workflow`, `.current_job`)
|
180
186
|
|
181
187
|
Each `Workflow` can be treated as a Redis-backed hash (all values will be coerced to strings). Combined with the fact that the current workflow context can always be accessed via `Sidekiq::Hierarchy.current_workflow` (nil if not in a workflow), you can pass arbitrary information through a work tree.
|
182
188
|
|
@@ -276,7 +282,7 @@ end
|
|
276
282
|
|
277
283
|
In the background, Sidekiq-hierarchy inserts and decodes two headers:
|
278
284
|
|
279
|
-
- Sidekiq-
|
285
|
+
- Sidekiq-Job: the job id of the parent worker, if any
|
280
286
|
- Sidekiq-Workflow: the workflow JID, if tracking is enabled (`workflow: true` in sidekiq_options)
|
281
287
|
|
282
288
|
Even if you are not using Faraday, adding these headers should be easy with your network library of choice.
|
@@ -340,14 +346,14 @@ On the server side, _inside_ the hierarchy middleware to ensure variables are se
|
|
340
346
|
```ruby
|
341
347
|
class FailFast::ServerMiddleware
|
342
348
|
def call(worker, job, queue)
|
343
|
-
|
349
|
+
current_job = Sidekiq::Hierarchy.current_job
|
344
350
|
workflow = Sidekiq::Hierarchy.current_workflow
|
345
351
|
return if workflow && workflow[:fail_fast]
|
346
352
|
|
347
353
|
yield
|
348
354
|
|
349
355
|
rescue => e
|
350
|
-
if workflow &&
|
356
|
+
if workflow && current_job.failed?
|
351
357
|
workflow[:fail_fast] = '1'
|
352
358
|
end
|
353
359
|
raise # make sure to propagate exception up
|
data/lib/sidekiq/hierarchy.rb
CHANGED
@@ -34,22 +34,22 @@ module Sidekiq
|
|
34
34
|
|
35
35
|
# Sets the workflow object for the current fiber/worker
|
36
36
|
def current_workflow=(workflow)
|
37
|
-
Thread.current[:
|
37
|
+
Thread.current[:sidekiq_hierarchy_workflow] = workflow
|
38
38
|
end
|
39
39
|
|
40
40
|
# Retrieves the current Sidekiq workflow if previously set
|
41
41
|
def current_workflow
|
42
|
-
Thread.current[:
|
42
|
+
Thread.current[:sidekiq_hierarchy_workflow]
|
43
43
|
end
|
44
44
|
|
45
|
-
# Sets the
|
46
|
-
def
|
47
|
-
Thread.current[:
|
45
|
+
# Sets the job for the current fiber/worker
|
46
|
+
def current_job=(job)
|
47
|
+
Thread.current[:sidekiq_hierarchy_job] = job
|
48
48
|
end
|
49
49
|
|
50
|
-
# Retrieves
|
51
|
-
def
|
52
|
-
Thread.current[:
|
50
|
+
# Retrieves job for the current Sidekiq job if previously set
|
51
|
+
def current_job
|
52
|
+
Thread.current[:sidekiq_hierarchy_job]
|
53
53
|
end
|
54
54
|
|
55
55
|
|
@@ -57,15 +57,14 @@ module Sidekiq
|
|
57
57
|
|
58
58
|
def record_job_enqueued(job)
|
59
59
|
return unless !!job['workflow']
|
60
|
-
if
|
60
|
+
if current_job.nil?
|
61
61
|
# this is a root-level job, i.e., start of a workflow
|
62
62
|
queued_job = Job.create(job['jid'], job)
|
63
63
|
queued_job.enqueue! # initial status: enqueued
|
64
|
-
elsif
|
64
|
+
elsif current_job.jid == job['jid']
|
65
65
|
# this is a job requeuing itself, ignore it
|
66
66
|
else
|
67
67
|
# this is an intermediate job, having both parent and children
|
68
|
-
current_job = Job.find(current_jid)
|
69
68
|
queued_job = Job.create(job['jid'], job)
|
70
69
|
current_job.add_child(queued_job)
|
71
70
|
queued_job.enqueue! # initial status: enqueued
|
@@ -73,23 +72,23 @@ module Sidekiq
|
|
73
72
|
end
|
74
73
|
|
75
74
|
def record_job_running
|
76
|
-
return unless enabled? &&
|
77
|
-
|
75
|
+
return unless enabled? && current_job
|
76
|
+
current_job.run!
|
78
77
|
end
|
79
78
|
|
80
79
|
def record_job_complete
|
81
|
-
return unless enabled? &&
|
82
|
-
|
80
|
+
return unless enabled? && current_job
|
81
|
+
current_job.complete!
|
83
82
|
end
|
84
83
|
|
85
84
|
def record_job_requeued
|
86
|
-
return unless enabled? &&
|
87
|
-
|
85
|
+
return unless enabled? && current_job
|
86
|
+
current_job.requeue!
|
88
87
|
end
|
89
88
|
|
90
89
|
def record_job_failed
|
91
|
-
return unless enabled? &&
|
92
|
-
|
90
|
+
return unless enabled? && current_job
|
91
|
+
current_job.fail!
|
93
92
|
end
|
94
93
|
|
95
94
|
|
@@ -6,8 +6,8 @@ module Sidekiq
|
|
6
6
|
module Faraday
|
7
7
|
class Middleware < ::Faraday::Middleware
|
8
8
|
def call(env)
|
9
|
-
if Sidekiq::Hierarchy.current_workflow && Sidekiq::Hierarchy.
|
10
|
-
env[:request_headers][Sidekiq::Hierarchy::Http::
|
9
|
+
if Sidekiq::Hierarchy.current_workflow && Sidekiq::Hierarchy.current_job
|
10
|
+
env[:request_headers][Sidekiq::Hierarchy::Http::JOB_HEADER] = Sidekiq::Hierarchy.current_job.jid
|
11
11
|
env[:request_headers][Sidekiq::Hierarchy::Http::WORKFLOW_HEADER] = Sidekiq::Hierarchy.current_workflow.jid
|
12
12
|
end
|
13
13
|
@app.call(env)
|
@@ -7,11 +7,16 @@ module Sidekiq
|
|
7
7
|
INFO_FIELD = 'i'.freeze
|
8
8
|
PARENT_FIELD = 'p'.freeze
|
9
9
|
STATUS_FIELD = 's'.freeze
|
10
|
-
|
10
|
+
|
11
11
|
ENQUEUED_AT_FIELD = 'e'.freeze
|
12
12
|
RUN_AT_FIELD = 'r'.freeze
|
13
13
|
COMPLETED_AT_FIELD = 'c'.freeze
|
14
14
|
|
15
|
+
WORKFLOW_STATUS_FIELD = 'w'.freeze
|
16
|
+
WORKFLOW_FINISHED_AT_FIELD = 'wf'.freeze
|
17
|
+
SUBTREE_SIZE_FIELD = 't'.freeze
|
18
|
+
FINISHED_SUBTREE_SIZE_FIELD = 'tf'.freeze
|
19
|
+
|
15
20
|
# Values for STATUS_FIELD
|
16
21
|
STATUS_ENQUEUED = '0'.freeze
|
17
22
|
STATUS_RUNNING = '1'.freeze
|
@@ -37,6 +42,7 @@ module Sidekiq
|
|
37
42
|
def create(jid, job_hash)
|
38
43
|
new(jid).tap do |job|
|
39
44
|
job[INFO_FIELD] = Sidekiq.dump_json(filtered_job_hash(job_hash))
|
45
|
+
job.increment_subtree_size # start at subtree size 1 -- no children
|
40
46
|
end
|
41
47
|
end
|
42
48
|
|
@@ -121,6 +127,44 @@ module Sidekiq
|
|
121
127
|
self.leaf? ? [self] : children.flat_map(&:leaves)
|
122
128
|
end
|
123
129
|
|
130
|
+
# Walks the subtree rooted here in DFS order
|
131
|
+
# Returns an Enumerator; use #to_a to get an array instead
|
132
|
+
def subtree_jobs
|
133
|
+
to_visit = [self]
|
134
|
+
Enumerator.new do |y|
|
135
|
+
while node = to_visit.pop
|
136
|
+
y << node # sugar for yielding a value
|
137
|
+
to_visit += node.children
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# The cached cardinality of the tree rooted at this job
|
143
|
+
def subtree_size
|
144
|
+
self[SUBTREE_SIZE_FIELD].to_i
|
145
|
+
end
|
146
|
+
|
147
|
+
# Recursively updates subtree size on this and all higher subtrees
|
148
|
+
def increment_subtree_size(incr=1)
|
149
|
+
redis { |conn| conn.hincrby(redis_job_hkey, SUBTREE_SIZE_FIELD, incr) }
|
150
|
+
if p_job = parent
|
151
|
+
p_job.increment_subtree_size(incr)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# The cached count of the finished jobs in the tree rooted at this job
|
156
|
+
def finished_subtree_size
|
157
|
+
self[FINISHED_SUBTREE_SIZE_FIELD].to_i
|
158
|
+
end
|
159
|
+
|
160
|
+
# Recursively updates finished subtree size on this and all higher subtrees
|
161
|
+
def increment_finished_subtree_size(incr=1)
|
162
|
+
redis { |conn| conn.hincrby(redis_job_hkey, FINISHED_SUBTREE_SIZE_FIELD, incr) }
|
163
|
+
if p_job = parent
|
164
|
+
p_job.increment_finished_subtree_size(incr)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
|
124
168
|
# Draws a new doubly-linked parent-child relationship in redis
|
125
169
|
def add_child(child_job)
|
126
170
|
redis do |conn|
|
@@ -133,7 +177,10 @@ module Sidekiq
|
|
133
177
|
conn.expire(redis_children_lkey, ONE_MONTH)
|
134
178
|
end
|
135
179
|
end
|
136
|
-
|
180
|
+
|
181
|
+
# updates subtree counts to reflect new child
|
182
|
+
increment_subtree_size(child_job.subtree_size)
|
183
|
+
increment_finished_subtree_size(child_job.finished_subtree_size)
|
137
184
|
end
|
138
185
|
|
139
186
|
def workflow
|
@@ -179,6 +226,7 @@ module Sidekiq
|
|
179
226
|
|
180
227
|
self[STATUS_FIELD] = s_val
|
181
228
|
self[t_field] = Time.now.to_f.to_s if t_field
|
229
|
+
increment_finished_subtree_size if [:failed, :complete].include?(new_status)
|
182
230
|
|
183
231
|
Sidekiq::Hierarchy.publish(Notifications::JOB_UPDATE, self, new_status, old_status)
|
184
232
|
end
|
@@ -250,6 +298,10 @@ module Sidekiq
|
|
250
298
|
end
|
251
299
|
end
|
252
300
|
|
301
|
+
def finished?
|
302
|
+
[:failed, :complete].include?(status) # two terminal states
|
303
|
+
end
|
304
|
+
|
253
305
|
def finished_at
|
254
306
|
if t = self[COMPLETED_AT_FIELD]
|
255
307
|
Time.at(t.to_f)
|
@@ -6,7 +6,7 @@ module Sidekiq
|
|
6
6
|
module Rack
|
7
7
|
class Middleware
|
8
8
|
# transform from http header to rack names
|
9
|
-
|
9
|
+
JOB_HEADER_KEY = "HTTP_#{Sidekiq::Hierarchy::Http::JOB_HEADER.upcase.gsub('-','_')}".freeze
|
10
10
|
WORKFLOW_HEADER_KEY = "HTTP_#{Sidekiq::Hierarchy::Http::WORKFLOW_HEADER.upcase.gsub('-','_')}".freeze
|
11
11
|
|
12
12
|
def initialize(app)
|
@@ -14,14 +14,14 @@ module Sidekiq
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def call(env)
|
17
|
-
if env[WORKFLOW_HEADER_KEY] && env[
|
18
|
-
Sidekiq::Hierarchy.
|
17
|
+
if env[WORKFLOW_HEADER_KEY] && env[JOB_HEADER_KEY]
|
18
|
+
Sidekiq::Hierarchy.current_job = Job.find(env[JOB_HEADER_KEY])
|
19
19
|
Sidekiq::Hierarchy.current_workflow = Workflow.find_by_jid(env[WORKFLOW_HEADER_KEY])
|
20
20
|
end
|
21
21
|
@app.call(env)
|
22
22
|
ensure
|
23
23
|
Sidekiq::Hierarchy.current_workflow = nil
|
24
|
-
Sidekiq::Hierarchy.
|
24
|
+
Sidekiq::Hierarchy.current_job = nil
|
25
25
|
end
|
26
26
|
end
|
27
27
|
end
|
@@ -14,10 +14,10 @@ module Sidekiq
|
|
14
14
|
def call(worker, msg, queue)
|
15
15
|
if msg['workflow'] == true # root job -- start of a new workflow
|
16
16
|
Sidekiq::Hierarchy.current_workflow = Workflow.find_by_jid(worker.jid)
|
17
|
-
Sidekiq::Hierarchy.
|
17
|
+
Sidekiq::Hierarchy.current_job = Sidekiq::Hierarchy.current_workflow.root
|
18
18
|
elsif msg['workflow'].is_a?(String) # child job -- inherit parent's workflow
|
19
19
|
Sidekiq::Hierarchy.current_workflow = Workflow.find_by_jid(msg['workflow'])
|
20
|
-
Sidekiq::Hierarchy.
|
20
|
+
Sidekiq::Hierarchy.current_job = Job.find(worker.jid)
|
21
21
|
end
|
22
22
|
|
23
23
|
Sidekiq::Hierarchy.record_job_running
|
@@ -34,18 +34,9 @@ module Sidekiq
|
|
34
34
|
wset.remove(self) if wset # now we can clear out from the set
|
35
35
|
end
|
36
36
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
to_visit = [root]
|
41
|
-
Enumerator.new do |y|
|
42
|
-
while node = to_visit.pop
|
43
|
-
y << node # sugar for yielding a value
|
44
|
-
to_visit += node.children
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
37
|
+
def_delegator :@root, :subtree_jobs, :jobs
|
38
|
+
def_delegator :@root, :subtree_size, :job_count
|
39
|
+
def_delegator :@root, :finished_subtree_size, :finished_job_count
|
49
40
|
|
50
41
|
### Status
|
51
42
|
|
@@ -70,12 +61,13 @@ module Sidekiq
|
|
70
61
|
new_status, s_val = :running, Job::STATUS_RUNNING
|
71
62
|
elsif from_job_status == :failed
|
72
63
|
new_status, s_val = :failed, Job::STATUS_FAILED
|
73
|
-
elsif from_job_status == :complete &&
|
64
|
+
elsif from_job_status == :complete && root.subtree_size == root.finished_subtree_size
|
74
65
|
new_status, s_val = :complete, Job::STATUS_COMPLETE
|
75
66
|
end
|
76
|
-
|
77
67
|
return if !new_status || new_status == old_status # don't publish null updates
|
68
|
+
|
78
69
|
self[Job::WORKFLOW_STATUS_FIELD] = s_val
|
70
|
+
self[Job::WORKFLOW_FINISHED_AT_FIELD] = Time.now.to_f.to_s if [:failed, :complete].include?(new_status)
|
79
71
|
|
80
72
|
Sidekiq::Hierarchy.publish(Notifications::WORKFLOW_UPDATE, self, new_status, old_status)
|
81
73
|
end
|
@@ -106,21 +98,25 @@ module Sidekiq
|
|
106
98
|
# Returns the time at which all jobs were complete;
|
107
99
|
# nil if any jobs are still incomplete
|
108
100
|
def complete_at
|
109
|
-
|
101
|
+
Time.at(self[Job::WORKFLOW_FINISHED_AT_FIELD].to_f) if complete?
|
110
102
|
end
|
111
103
|
|
112
104
|
# Returns the earliest time at which a job failed;
|
113
105
|
# nil if none did
|
114
106
|
def failed_at
|
115
|
-
|
107
|
+
Time.at(self[Job::WORKFLOW_FINISHED_AT_FIELD].to_f) if failed?
|
108
|
+
end
|
109
|
+
|
110
|
+
def finished_at
|
111
|
+
if timestamp = self[Job::WORKFLOW_FINISHED_AT_FIELD]
|
112
|
+
Time.at(timestamp.to_f)
|
113
|
+
end
|
116
114
|
end
|
117
115
|
|
118
116
|
|
119
117
|
### Serialisation
|
120
118
|
|
121
|
-
|
122
|
-
root.as_json(options)
|
123
|
-
end
|
119
|
+
delegate :as_json => :@root
|
124
120
|
|
125
121
|
def to_s
|
126
122
|
Sidekiq.dump_json(self.as_json)
|
@@ -8,7 +8,7 @@
|
|
8
8
|
<th>Run at</th>
|
9
9
|
<th>Completed at</th>
|
10
10
|
<th>Failed at</th>
|
11
|
-
<th>
|
11
|
+
<th>Completion</th>
|
12
12
|
</tr>
|
13
13
|
</thead>
|
14
14
|
|
@@ -25,7 +25,7 @@
|
|
25
25
|
<td><%= workflow.run_at %></td>
|
26
26
|
<td><%= workflow.complete_at %></td>
|
27
27
|
<td><%= workflow.failed_at %></td>
|
28
|
-
<td><%= workflow.
|
28
|
+
<td><%= workflow.finished_job_count %>/<%= workflow.job_count %></td>
|
29
29
|
</tr>
|
30
30
|
<% end%>
|
31
31
|
</tbody>
|
@@ -5,12 +5,14 @@
|
|
5
5
|
</span>
|
6
6
|
(<%= job.info['queue'] %>)
|
7
7
|
<span class="label label-<%= bootstrap_status(job.status) %>">
|
8
|
-
<%= job.status %> <%=
|
8
|
+
<%= job.status %> <%= safe_relative_time(status_updated_at(job)) %>
|
9
9
|
</span>
|
10
10
|
</a>
|
11
|
-
|
11
|
+
|
12
|
+
<%- children = job.children %>
|
13
|
+
<% if children.any? %>
|
12
14
|
<ul>
|
13
|
-
<%
|
15
|
+
<% children.each do |child| %>
|
14
16
|
<%= erb :_workflow_tree_node, locals: {job: child} %>
|
15
17
|
<% end %>
|
16
18
|
</ul>
|
data/web/views/status.erb
CHANGED
@@ -19,6 +19,7 @@
|
|
19
19
|
<th>Workflow ID</th>
|
20
20
|
<th>Enqueued at</th>
|
21
21
|
<th>Run at</th>
|
22
|
+
<th>Completion</th>
|
22
23
|
</tr>
|
23
24
|
</thead>
|
24
25
|
|
@@ -30,8 +31,9 @@
|
|
30
31
|
<%= workflow.jid %>
|
31
32
|
</a>
|
32
33
|
</td>
|
33
|
-
<td><%=
|
34
|
-
<td><%=
|
34
|
+
<td><%= safe_relative_time(workflow.enqueued_at) %></td>
|
35
|
+
<td><%= safe_relative_time(workflow.run_at) if workflow.run_at %></td>
|
36
|
+
<td><%= workflow.finished_job_count %>/<%= workflow.job_count %></td>
|
35
37
|
</tr>
|
36
38
|
<% end%>
|
37
39
|
</tbody>
|
@@ -57,6 +59,7 @@
|
|
57
59
|
<th>Enqueued at</th>
|
58
60
|
<th>Run at</th>
|
59
61
|
<th>Completed at</th>
|
62
|
+
<th>Job count</th>
|
60
63
|
</tr>
|
61
64
|
</thead>
|
62
65
|
|
@@ -68,9 +71,10 @@
|
|
68
71
|
<%= workflow.jid %>
|
69
72
|
</a>
|
70
73
|
</td>
|
71
|
-
<td><%=
|
72
|
-
<td><%=
|
73
|
-
<td><%=
|
74
|
+
<td><%= safe_relative_time(workflow.enqueued_at) %></td>
|
75
|
+
<td><%= safe_relative_time(workflow.run_at) %></td>
|
76
|
+
<td><%= safe_relative_time(workflow.complete_at) %></td>
|
77
|
+
<td><%= workflow.job_count %></td>
|
74
78
|
</tr>
|
75
79
|
<% end%>
|
76
80
|
</tbody>
|
@@ -98,6 +102,7 @@
|
|
98
102
|
<th>Enqueued at</th>
|
99
103
|
<th>Run at</th>
|
100
104
|
<th>Failed at</th>
|
105
|
+
<th>Job count</th>
|
101
106
|
</tr>
|
102
107
|
</thead>
|
103
108
|
|
@@ -109,9 +114,10 @@
|
|
109
114
|
<%= workflow.jid %>
|
110
115
|
</a>
|
111
116
|
</td>
|
112
|
-
<td><%=
|
113
|
-
<td><%=
|
114
|
-
<td><%=
|
117
|
+
<td><%= safe_relative_time(workflow.enqueued_at) %></td>
|
118
|
+
<td><%= safe_relative_time(workflow.run_at) %></td>
|
119
|
+
<td><%= safe_relative_time(workflow.failed_at) %></td>
|
120
|
+
<td><%= workflow.job_count %></td>
|
115
121
|
</tr>
|
116
122
|
<% end %>
|
117
123
|
</tbody>
|
data/web/views/workflow.erb
CHANGED
@@ -11,6 +11,7 @@
|
|
11
11
|
<th>Run at</th>
|
12
12
|
<th>Completed at</th>
|
13
13
|
<th>Failed at</th>
|
14
|
+
<th>Completion</th>
|
14
15
|
</tr>
|
15
16
|
</thead>
|
16
17
|
|
@@ -21,6 +22,7 @@
|
|
21
22
|
<td><%= @workflow.run_at %></td>
|
22
23
|
<td><%= @workflow.complete_at %></td>
|
23
24
|
<td><%= @workflow.failed_at %></td>
|
25
|
+
<td><%= @workflow.finished_job_count %>/<%= @workflow.job_count %></td>
|
24
26
|
</tr>
|
25
27
|
</tbody>
|
26
28
|
</table>
|
metadata
CHANGED
@@ -1,167 +1,168 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sidekiq-hierarchy
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Anuj Das
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
11
|
date: 2015-12-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
+
name: sidekiq
|
14
15
|
requirement: !ruby/object:Gem::Requirement
|
15
16
|
requirements:
|
16
|
-
- - ~>
|
17
|
+
- - "~>"
|
17
18
|
- !ruby/object:Gem::Version
|
18
19
|
version: '3.3'
|
19
|
-
name: sidekiq
|
20
|
-
prerelease: false
|
21
20
|
type: :runtime
|
21
|
+
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '3.3'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
+
name: connection_pool
|
28
29
|
requirement: !ruby/object:Gem::Requirement
|
29
30
|
requirements:
|
30
|
-
- - ~>
|
31
|
+
- - "~>"
|
31
32
|
- !ruby/object:Gem::Version
|
32
33
|
version: '2.0'
|
33
|
-
name: connection_pool
|
34
|
-
prerelease: false
|
35
34
|
type: :runtime
|
35
|
+
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- - ~>
|
38
|
+
- - "~>"
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '2.0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
42
43
|
requirement: !ruby/object:Gem::Requirement
|
43
44
|
requirements:
|
44
|
-
- - ~>
|
45
|
+
- - "~>"
|
45
46
|
- !ruby/object:Gem::Version
|
46
47
|
version: '1.10'
|
47
|
-
name: bundler
|
48
|
-
prerelease: false
|
49
48
|
type: :development
|
49
|
+
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - ~>
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '1.10'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
56
57
|
requirement: !ruby/object:Gem::Requirement
|
57
58
|
requirements:
|
58
|
-
- - ~>
|
59
|
+
- - "~>"
|
59
60
|
- !ruby/object:Gem::Version
|
60
61
|
version: '10.0'
|
61
|
-
name: rake
|
62
|
-
prerelease: false
|
63
62
|
type: :development
|
63
|
+
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - ~>
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '10.0'
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
70
71
|
requirement: !ruby/object:Gem::Requirement
|
71
72
|
requirements:
|
72
|
-
- - ~>
|
73
|
+
- - "~>"
|
73
74
|
- !ruby/object:Gem::Version
|
74
75
|
version: '3.0'
|
75
|
-
name: rspec
|
76
|
-
prerelease: false
|
77
76
|
type: :development
|
77
|
+
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - ~>
|
80
|
+
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '3.0'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec-its
|
84
85
|
requirement: !ruby/object:Gem::Requirement
|
85
86
|
requirements:
|
86
|
-
- -
|
87
|
+
- - ">="
|
87
88
|
- !ruby/object:Gem::Version
|
88
89
|
version: '0'
|
89
|
-
name: rspec-its
|
90
|
-
prerelease: false
|
91
90
|
type: :development
|
91
|
+
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- -
|
94
|
+
- - ">="
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '0'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
|
+
name: fakeredis
|
98
99
|
requirement: !ruby/object:Gem::Requirement
|
99
100
|
requirements:
|
100
|
-
- -
|
101
|
+
- - ">="
|
101
102
|
- !ruby/object:Gem::Version
|
102
103
|
version: '0'
|
103
|
-
name: fakeredis
|
104
|
-
prerelease: false
|
105
104
|
type: :development
|
105
|
+
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- -
|
108
|
+
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
|
+
name: rspec-sidekiq
|
112
113
|
requirement: !ruby/object:Gem::Requirement
|
113
114
|
requirements:
|
114
|
-
- -
|
115
|
+
- - ">="
|
115
116
|
- !ruby/object:Gem::Version
|
116
117
|
version: '0'
|
117
|
-
name: rspec-sidekiq
|
118
|
-
prerelease: false
|
119
118
|
type: :development
|
119
|
+
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
|
-
- -
|
122
|
+
- - ">="
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: '0'
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
|
+
name: faraday
|
126
127
|
requirement: !ruby/object:Gem::Requirement
|
127
128
|
requirements:
|
128
|
-
- -
|
129
|
+
- - ">="
|
129
130
|
- !ruby/object:Gem::Version
|
130
131
|
version: '0'
|
131
|
-
name: faraday
|
132
|
-
prerelease: false
|
133
132
|
type: :development
|
133
|
+
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
|
-
- -
|
136
|
+
- - ">="
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: '0'
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
|
+
name: rack
|
140
141
|
requirement: !ruby/object:Gem::Requirement
|
141
142
|
requirements:
|
142
|
-
- -
|
143
|
+
- - ">="
|
143
144
|
- !ruby/object:Gem::Version
|
144
145
|
version: '0'
|
145
|
-
name: rack
|
146
|
-
prerelease: false
|
147
146
|
type: :development
|
147
|
+
prerelease: false
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
149
149
|
requirements:
|
150
|
-
- -
|
150
|
+
- - ">="
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: '0'
|
153
|
-
description: A set of sidekiq middlewares to track workflows consisting of multiple
|
153
|
+
description: A set of sidekiq middlewares to track workflows consisting of multiple
|
154
|
+
levels of sidekiq jobs
|
154
155
|
email:
|
155
156
|
- anujdas@gmail.com
|
156
157
|
executables: []
|
157
158
|
extensions: []
|
158
159
|
extra_rdoc_files: []
|
159
160
|
files:
|
160
|
-
- .gitignore
|
161
|
-
- .rspec
|
162
|
-
- .ruby-gemset
|
163
|
-
- .ruby-version
|
164
|
-
- .travis.yml
|
161
|
+
- ".gitignore"
|
162
|
+
- ".rspec"
|
163
|
+
- ".ruby-gemset"
|
164
|
+
- ".ruby-version"
|
165
|
+
- ".travis.yml"
|
165
166
|
- CHANGELOG.md
|
166
167
|
- CONTRIBUTING.md
|
167
168
|
- Gemfile
|
@@ -215,24 +216,25 @@ homepage: https://www.github.com/anujdas/sidekiq-hierarchy
|
|
215
216
|
licenses:
|
216
217
|
- MIT
|
217
218
|
metadata: {}
|
218
|
-
post_install_message:
|
219
|
+
post_install_message:
|
219
220
|
rdoc_options: []
|
220
221
|
require_paths:
|
221
222
|
- lib
|
222
223
|
required_ruby_version: !ruby/object:Gem::Requirement
|
223
224
|
requirements:
|
224
|
-
- -
|
225
|
+
- - ">="
|
225
226
|
- !ruby/object:Gem::Version
|
226
227
|
version: '0'
|
227
228
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
228
229
|
requirements:
|
229
|
-
- -
|
230
|
+
- - ">="
|
230
231
|
- !ruby/object:Gem::Version
|
231
232
|
version: '0'
|
232
233
|
requirements: []
|
233
|
-
rubyforge_project:
|
234
|
-
rubygems_version: 2.4.
|
235
|
-
signing_key:
|
234
|
+
rubyforge_project:
|
235
|
+
rubygems_version: 2.4.5.1
|
236
|
+
signing_key:
|
236
237
|
specification_version: 4
|
237
|
-
summary: A set of sidekiq middlewares to track workflows consisting of multiple levels
|
238
|
+
summary: A set of sidekiq middlewares to track workflows consisting of multiple levels
|
239
|
+
of sidekiq jobs
|
238
240
|
test_files: []
|