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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7bbc58dd27887b22cd4028b50d0baa627155c604
4
- data.tar.gz: a19dd469928472862f286c9408471b898f30f839
3
+ metadata.gz: 7da49b3d427ff6aad77da49fbf6aedcbaf9ba70b
4
+ data.tar.gz: 9ac4dcc0972bba86b7d251ef73be6297fc19627b
5
5
  SHA512:
6
- metadata.gz: cadcdc2e2ab393ecae67ea16f8cc7a609df3e00f30e43b1d144f8dd1706f141646156708afd17ddfb37b54b75235987c4cdf45f55226e29ec36c1cdb18d248a0
7
- data.tar.gz: 37e3e7654896e53377e4b462f76282dafabaa8967fb22827c4d1c0df08fc9bd8b023cf555c40933c238ea56a905bdea7cfc1c29480382f035b7b8636edb39839
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 id context (`Sidekiq::Hierarchy.current_workflow`, `.current_jid`)
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-Jid: the job id of the parent worker, if any
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
- current_jid = Sidekiq::Hierarchy.current_jid
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 && Sidekiq::Hierarchy::Job.find(current_jid).failed?
356
+ if workflow && current_job.failed?
351
357
  workflow[:fail_fast] = '1'
352
358
  end
353
359
  raise # make sure to propagate exception up
@@ -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[:workflow] = workflow
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[:workflow]
42
+ Thread.current[:sidekiq_hierarchy_workflow]
43
43
  end
44
44
 
45
- # Sets the jid for the current fiber/worker
46
- def current_jid=(jid)
47
- Thread.current[:jid] = jid
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 jid for the current Sidekiq job if previously set
51
- def current_jid
52
- Thread.current[:jid]
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 current_jid.nil?
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 current_jid == job['jid']
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? && current_jid
77
- Job.find(current_jid).run!
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? && current_jid
82
- Job.find(current_jid).complete!
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? && current_jid
87
- Job.find(current_jid).requeue!
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? && current_jid
92
- Job.find(current_jid).fail!
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.current_jid
10
- env[:request_headers][Sidekiq::Hierarchy::Http::JID_HEADER] = Sidekiq::Hierarchy.current_jid
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)
@@ -1,7 +1,7 @@
1
1
  module Sidekiq
2
2
  module Hierarchy
3
3
  module Http
4
- JID_HEADER = 'Sidekiq-Jid'.freeze
4
+ JOB_HEADER = 'Sidekiq-Job'.freeze
5
5
  WORKFLOW_HEADER = 'Sidekiq-Workflow'.freeze
6
6
  end
7
7
  end
@@ -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
- WORKFLOW_STATUS_FIELD = 'w'.freeze
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
- true # will never fail w/o raising an exception
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
- JID_HEADER_KEY = "HTTP_#{Sidekiq::Hierarchy::Http::JID_HEADER.upcase.gsub('-','_')}".freeze
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[JID_HEADER_KEY]
18
- Sidekiq::Hierarchy.current_jid = env[JID_HEADER_KEY]
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.current_jid = nil
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.current_jid = worker.jid
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.current_jid = worker.jid
20
+ Sidekiq::Hierarchy.current_job = Job.find(worker.jid)
21
21
  end
22
22
 
23
23
  Sidekiq::Hierarchy.record_job_running
@@ -1,5 +1,5 @@
1
1
  module Sidekiq
2
2
  module Hierarchy
3
- VERSION = '1.1.0'
3
+ VERSION = '2.0.0'
4
4
  end
5
5
  end
@@ -28,6 +28,10 @@ module Sidekiq
28
28
  "#{root_path}hierarchy/workflow_sets/#{status}"
29
29
  end
30
30
 
31
+ def safe_relative_time(timestamp)
32
+ timestamp.nil? ? '-' : relative_time(timestamp)
33
+ end
34
+
31
35
  def status_updated_at(job)
32
36
  case job.status
33
37
  when :enqueued
@@ -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
- # Walks the tree in DFS order (for optimal completion checking)
38
- # Returns an Enumerator; use #to_a to get an array instead
39
- def jobs
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 && jobs.all?(&: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
- jobs.map(&:complete_at).max if complete?
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
- jobs.map(&:failed_at).compact.min if failed?
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
- def as_json(options={})
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>Jobs</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.jobs.count %></td>
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 %> <%= relative_time(status_updated_at(job)) %>
8
+ <%= job.status %> <%= safe_relative_time(status_updated_at(job)) %>
9
9
  </span>
10
10
  </a>
11
- <% unless job.leaf? %>
11
+
12
+ <%- children = job.children %>
13
+ <% if children.any? %>
12
14
  <ul>
13
- <% job.children.each do |child| %>
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><%= relative_time(workflow.enqueued_at) %></td>
34
- <td><%= relative_time(workflow.run_at) if workflow.run_at %></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><%= relative_time(workflow.enqueued_at) %></td>
72
- <td><%= relative_time(workflow.run_at) %></td>
73
- <td><%= relative_time(workflow.complete_at) %></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><%= relative_time(workflow.enqueued_at) %></td>
113
- <td><%= relative_time(workflow.run_at) %></td>
114
- <td><%= relative_time(workflow.failed_at) %></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>
@@ -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: 1.1.0
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 levels of sidekiq jobs
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.8
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 of sidekiq jobs
238
+ summary: A set of sidekiq middlewares to track workflows consisting of multiple levels
239
+ of sidekiq jobs
238
240
  test_files: []