solid-jobs 0.1.2 → 0.2.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 +38 -2
- data/README.md +137 -117
- data/docs/reliability.md +71 -89
- data/lib/active_job/queue_adapters/solid_jobs_adapter.rb +6 -7
- data/lib/solid_jobs/active_job.rb +2 -5
- data/lib/solid_jobs/api.rb +133 -156
- data/lib/solid_jobs/claim.rb +315 -0
- data/lib/solid_jobs/cli.rb +9 -6
- data/lib/solid_jobs/config.rb +50 -50
- data/lib/solid_jobs/executor.rb +34 -0
- data/lib/solid_jobs/failure_policy.rb +98 -0
- data/lib/solid_jobs/heartbeat.rb +15 -13
- data/lib/solid_jobs/integrity_check.rb +39 -36
- data/lib/solid_jobs/interceptor_registry.rb +57 -0
- data/lib/solid_jobs/keyspace.rb +42 -0
- data/lib/solid_jobs/processor.rb +30 -30
- data/lib/solid_jobs/publisher.rb +186 -0
- data/lib/solid_jobs/recovery.rb +8 -7
- data/lib/solid_jobs/server.rb +2 -2
- data/lib/solid_jobs/task.rb +147 -0
- data/lib/solid_jobs/testing.rb +18 -18
- data/lib/solid_jobs/{scheduler.rb → timer.rb} +8 -8
- data/lib/solid_jobs/version.rb +1 -2
- data/lib/solid_jobs.rb +18 -18
- metadata +13 -32
- data/lib/solid_jobs/client.rb +0 -202
- data/lib/solid_jobs/fetch.rb +0 -310
- data/lib/solid_jobs/job.rb +0 -156
- data/lib/solid_jobs/middleware/chain.rb +0 -104
- data/lib/solid_jobs/retry_service.rb +0 -100
- data/lib/solid_jobs/worker.rb +0 -35
data/lib/solid_jobs/api.rb
CHANGED
|
@@ -3,72 +3,68 @@
|
|
|
3
3
|
require "json"
|
|
4
4
|
|
|
5
5
|
module SolidJobs
|
|
6
|
-
class
|
|
6
|
+
class Metrics
|
|
7
7
|
attr_reader :config
|
|
8
8
|
|
|
9
9
|
def initialize(config: SolidJobs.config)
|
|
10
10
|
@config = config
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
def
|
|
14
|
-
|
|
13
|
+
def completed
|
|
14
|
+
counter(Keyspace::PROCESSED)
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def failed
|
|
18
|
-
|
|
18
|
+
counter(Keyspace::FAILED)
|
|
19
19
|
end
|
|
20
20
|
|
|
21
|
-
def
|
|
22
|
-
|
|
21
|
+
def ready
|
|
22
|
+
Channel.catalog(config: config).sum(&:size)
|
|
23
23
|
end
|
|
24
24
|
|
|
25
|
-
def
|
|
26
|
-
|
|
25
|
+
def planned
|
|
26
|
+
cardinality(Keyspace::PLANNED)
|
|
27
27
|
end
|
|
28
28
|
|
|
29
|
-
def
|
|
30
|
-
|
|
29
|
+
def retrying
|
|
30
|
+
cardinality(Keyspace::RETRIES)
|
|
31
31
|
end
|
|
32
32
|
|
|
33
|
-
def
|
|
34
|
-
|
|
33
|
+
def discarded
|
|
34
|
+
cardinality(Keyspace::DISCARDED)
|
|
35
35
|
end
|
|
36
36
|
|
|
37
|
-
def
|
|
38
|
-
|
|
37
|
+
def nodes
|
|
38
|
+
Integer(config.redis_pool.call("SCARD", Keyspace::NODES))
|
|
39
39
|
end
|
|
40
40
|
|
|
41
|
-
def
|
|
42
|
-
|
|
41
|
+
def executions
|
|
42
|
+
Nodes.new(config: config).sum(&:active_count)
|
|
43
43
|
end
|
|
44
44
|
|
|
45
45
|
def reset
|
|
46
|
-
config.redis_pool.call("DEL",
|
|
46
|
+
config.redis_pool.call("DEL", Keyspace::PROCESSED, Keyspace::FAILED)
|
|
47
47
|
self
|
|
48
48
|
end
|
|
49
49
|
|
|
50
50
|
private
|
|
51
51
|
|
|
52
|
-
def
|
|
53
|
-
Queue.all(config: config)
|
|
54
|
-
end
|
|
55
|
-
|
|
56
|
-
def integer(key)
|
|
52
|
+
def counter(key)
|
|
57
53
|
Integer(config.redis_pool.call("GET", key) || 0)
|
|
58
54
|
end
|
|
59
55
|
|
|
60
|
-
def
|
|
61
|
-
Integer(config.redis_pool.call(
|
|
56
|
+
def cardinality(key)
|
|
57
|
+
Integer(config.redis_pool.call("ZCARD", key))
|
|
62
58
|
end
|
|
63
59
|
end
|
|
64
60
|
|
|
65
|
-
class
|
|
61
|
+
class Channel
|
|
66
62
|
include Enumerable
|
|
67
63
|
|
|
68
64
|
attr_reader :name
|
|
69
65
|
|
|
70
|
-
def self.
|
|
71
|
-
Array(config.redis_pool.call("SMEMBERS",
|
|
66
|
+
def self.catalog(config: SolidJobs.config)
|
|
67
|
+
Array(config.redis_pool.call("SMEMBERS", Keyspace::CHANNELS)).sort.map do |name|
|
|
72
68
|
new(name, config: config)
|
|
73
69
|
end
|
|
74
70
|
end
|
|
@@ -81,191 +77,180 @@ module SolidJobs
|
|
|
81
77
|
def each
|
|
82
78
|
return enum_for(:each) unless block_given?
|
|
83
79
|
|
|
84
|
-
Array(@config.redis_pool.call("LRANGE",
|
|
85
|
-
yield
|
|
80
|
+
Array(@config.redis_pool.call("LRANGE", storage_key, 0, -1)).reverse_each do |raw|
|
|
81
|
+
yield StoredTask.new(raw, config: @config, owner: self)
|
|
86
82
|
end
|
|
87
83
|
end
|
|
88
84
|
|
|
89
85
|
def size
|
|
90
|
-
Integer(@config.redis_pool.call("LLEN",
|
|
86
|
+
Integer(@config.redis_pool.call("LLEN", storage_key))
|
|
91
87
|
end
|
|
92
|
-
alias_method :length, :size
|
|
93
88
|
|
|
94
|
-
def
|
|
95
|
-
raw = @config.redis_pool.call("LINDEX",
|
|
89
|
+
def waiting_time
|
|
90
|
+
raw = @config.redis_pool.call("LINDEX", storage_key, -1)
|
|
96
91
|
return 0.0 unless raw
|
|
97
92
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
[Time.now.to_f - Float(enqueued_at) / 1_000, 0.0].max
|
|
93
|
+
envelope = JSON.parse(raw)
|
|
94
|
+
timestamp = envelope["queued_ms"] || envelope["created_ms"]
|
|
95
|
+
timestamp ? [Time.now.to_f - Float(timestamp) / 1_000, 0.0].max : 0.0
|
|
103
96
|
end
|
|
104
97
|
|
|
105
|
-
def
|
|
106
|
-
@config.redis_pool.call("DEL", key)
|
|
107
|
-
self
|
|
108
|
-
end
|
|
109
|
-
|
|
110
|
-
def delete
|
|
98
|
+
def purge
|
|
111
99
|
@config.redis_pool.pipelined do |pipeline|
|
|
112
|
-
pipeline.call("DEL",
|
|
113
|
-
pipeline.call("SREM",
|
|
100
|
+
pipeline.call("DEL", storage_key)
|
|
101
|
+
pipeline.call("SREM", Keyspace::CHANNELS, name)
|
|
114
102
|
end
|
|
115
103
|
self
|
|
116
104
|
end
|
|
117
105
|
|
|
118
106
|
def paused?
|
|
119
|
-
|
|
107
|
+
Integer(@config.redis_pool.call("SISMEMBER", Keyspace::PAUSED_CHANNELS, name)) == 1
|
|
120
108
|
end
|
|
121
109
|
|
|
122
110
|
def pause
|
|
123
|
-
@config.redis_pool.call("SADD",
|
|
111
|
+
@config.redis_pool.call("SADD", Keyspace::PAUSED_CHANNELS, name)
|
|
124
112
|
self
|
|
125
113
|
end
|
|
126
114
|
|
|
127
|
-
def
|
|
128
|
-
@config.redis_pool.call("SREM",
|
|
115
|
+
def resume
|
|
116
|
+
@config.redis_pool.call("SREM", Keyspace::PAUSED_CHANNELS, name)
|
|
129
117
|
self
|
|
130
118
|
end
|
|
131
119
|
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
def key
|
|
135
|
-
"queue:#{name}"
|
|
120
|
+
def storage_key
|
|
121
|
+
Keyspace.channel(name)
|
|
136
122
|
end
|
|
137
123
|
end
|
|
138
124
|
|
|
139
|
-
class
|
|
140
|
-
attr_reader :
|
|
125
|
+
class StoredTask
|
|
126
|
+
attr_reader :envelope, :score
|
|
141
127
|
|
|
142
|
-
def initialize(raw, score: nil, config: SolidJobs.config,
|
|
128
|
+
def initialize(raw, score: nil, config: SolidJobs.config, owner: nil)
|
|
143
129
|
@raw = raw
|
|
144
|
-
@
|
|
130
|
+
@envelope = JSON.parse(raw)
|
|
145
131
|
@score = Float(score) if score
|
|
146
132
|
@config = config
|
|
147
|
-
@
|
|
133
|
+
@owner = owner
|
|
148
134
|
end
|
|
149
135
|
|
|
150
|
-
def
|
|
151
|
-
|
|
136
|
+
def id
|
|
137
|
+
envelope["id"]
|
|
152
138
|
end
|
|
153
139
|
|
|
154
|
-
def
|
|
155
|
-
|
|
140
|
+
def channel
|
|
141
|
+
envelope["channel"]
|
|
156
142
|
end
|
|
157
143
|
|
|
158
|
-
def
|
|
159
|
-
|
|
144
|
+
def task
|
|
145
|
+
envelope["task"]
|
|
160
146
|
end
|
|
161
147
|
|
|
162
|
-
def
|
|
163
|
-
|
|
148
|
+
def arguments
|
|
149
|
+
envelope["arguments"]
|
|
164
150
|
end
|
|
165
151
|
|
|
166
152
|
def created_at
|
|
167
|
-
|
|
153
|
+
millisecond_time(envelope["created_ms"])
|
|
168
154
|
end
|
|
169
155
|
|
|
170
|
-
def
|
|
171
|
-
|
|
156
|
+
def queued_at
|
|
157
|
+
millisecond_time(envelope["queued_ms"])
|
|
172
158
|
end
|
|
173
159
|
|
|
174
|
-
def
|
|
160
|
+
def due_at
|
|
175
161
|
Time.at(score) if score
|
|
176
162
|
end
|
|
177
163
|
|
|
178
|
-
def
|
|
179
|
-
case @
|
|
180
|
-
when
|
|
181
|
-
@config.redis_pool.call("ZREM", @
|
|
182
|
-
when
|
|
183
|
-
@config.redis_pool.call("LREM",
|
|
164
|
+
def remove
|
|
165
|
+
case @owner
|
|
166
|
+
when TimedTasks
|
|
167
|
+
@config.redis_pool.call("ZREM", @owner.key, @raw)
|
|
168
|
+
when Channel
|
|
169
|
+
@config.redis_pool.call("LREM", @owner.storage_key, 1, @raw)
|
|
184
170
|
else
|
|
185
171
|
false
|
|
186
172
|
end
|
|
187
173
|
end
|
|
188
174
|
|
|
189
|
-
def
|
|
190
|
-
|
|
191
|
-
|
|
175
|
+
def requeue
|
|
176
|
+
remove
|
|
177
|
+
Publisher.new(config: @config).publish(envelope)
|
|
192
178
|
end
|
|
193
179
|
|
|
194
180
|
private
|
|
195
181
|
|
|
196
|
-
def
|
|
182
|
+
def millisecond_time(value)
|
|
197
183
|
Time.at(Float(value) / 1_000) if value
|
|
198
184
|
end
|
|
199
185
|
end
|
|
200
186
|
|
|
201
|
-
class
|
|
187
|
+
class TimedTasks
|
|
202
188
|
include Enumerable
|
|
203
189
|
|
|
204
|
-
attr_reader :
|
|
190
|
+
attr_reader :key
|
|
205
191
|
|
|
206
|
-
def initialize(
|
|
207
|
-
@
|
|
192
|
+
def initialize(key, config: SolidJobs.config)
|
|
193
|
+
@key = key
|
|
208
194
|
@config = config
|
|
209
195
|
end
|
|
210
196
|
|
|
211
197
|
def each
|
|
212
198
|
return enum_for(:each) unless block_given?
|
|
213
199
|
|
|
214
|
-
values = Array(@config.redis_pool.call("ZRANGE",
|
|
200
|
+
values = Array(@config.redis_pool.call("ZRANGE", key, 0, -1, "WITHSCORES"))
|
|
215
201
|
values.each_slice(2) do |raw, score|
|
|
216
|
-
yield
|
|
202
|
+
yield StoredTask.new(raw, score: score, config: @config, owner: self)
|
|
217
203
|
end
|
|
218
204
|
end
|
|
219
205
|
|
|
220
206
|
def size
|
|
221
|
-
Integer(@config.redis_pool.call("ZCARD",
|
|
207
|
+
Integer(@config.redis_pool.call("ZCARD", key))
|
|
222
208
|
end
|
|
223
|
-
alias_method :length, :size
|
|
224
209
|
|
|
225
|
-
def
|
|
226
|
-
@config.redis_pool.call("DEL",
|
|
210
|
+
def purge
|
|
211
|
+
@config.redis_pool.call("DEL", key)
|
|
227
212
|
self
|
|
228
213
|
end
|
|
229
214
|
|
|
230
|
-
def
|
|
231
|
-
wanted =
|
|
232
|
-
select { |
|
|
215
|
+
def locate(*ids)
|
|
216
|
+
wanted = ids.flatten
|
|
217
|
+
select { |task| wanted.include?(task.id) }
|
|
233
218
|
end
|
|
234
219
|
end
|
|
235
220
|
|
|
236
|
-
class
|
|
221
|
+
class PlannedTasks < TimedTasks
|
|
237
222
|
def initialize(config: SolidJobs.config)
|
|
238
|
-
super(
|
|
223
|
+
super(Keyspace::PLANNED, config: config)
|
|
239
224
|
end
|
|
240
225
|
end
|
|
241
226
|
|
|
242
|
-
class
|
|
227
|
+
class RetryingTasks < TimedTasks
|
|
243
228
|
def initialize(config: SolidJobs.config)
|
|
244
|
-
super(
|
|
229
|
+
super(Keyspace::RETRIES, config: config)
|
|
245
230
|
end
|
|
246
231
|
|
|
247
|
-
def
|
|
248
|
-
each.to_a.each(&:
|
|
232
|
+
def requeue_all
|
|
233
|
+
each.to_a.each(&:requeue)
|
|
249
234
|
end
|
|
250
235
|
end
|
|
251
236
|
|
|
252
|
-
class
|
|
237
|
+
class DiscardedTasks < TimedTasks
|
|
253
238
|
def initialize(config: SolidJobs.config)
|
|
254
|
-
super(
|
|
239
|
+
super(Keyspace::DISCARDED, config: config)
|
|
255
240
|
end
|
|
256
241
|
|
|
257
|
-
def
|
|
258
|
-
each.to_a.each(&:
|
|
242
|
+
def requeue_all
|
|
243
|
+
each.to_a.each(&:requeue)
|
|
259
244
|
end
|
|
260
245
|
end
|
|
261
246
|
|
|
262
|
-
class
|
|
247
|
+
class Node
|
|
263
248
|
attr_reader :identity
|
|
264
249
|
|
|
265
250
|
def initialize(identity, config: SolidJobs.config)
|
|
266
251
|
@identity = identity
|
|
267
252
|
@config = config
|
|
268
|
-
fields = Array(@config.redis_pool.call("HGETALL", identity))
|
|
253
|
+
fields = Array(@config.redis_pool.call("HGETALL", Keyspace.node(identity)))
|
|
269
254
|
@attributes = fields.each_slice(2).to_h
|
|
270
255
|
@info = JSON.parse(@attributes.fetch("info", "{}"))
|
|
271
256
|
end
|
|
@@ -278,11 +263,11 @@ module SolidJobs
|
|
|
278
263
|
Integer(@info["pid"] || 0)
|
|
279
264
|
end
|
|
280
265
|
|
|
281
|
-
def
|
|
282
|
-
@info["
|
|
266
|
+
def channels
|
|
267
|
+
@info["channels"] || []
|
|
283
268
|
end
|
|
284
269
|
|
|
285
|
-
def
|
|
270
|
+
def active_count
|
|
286
271
|
Integer(@attributes["busy"] || 0)
|
|
287
272
|
end
|
|
288
273
|
|
|
@@ -294,15 +279,15 @@ module SolidJobs
|
|
|
294
279
|
@attributes["quiet"] == "true"
|
|
295
280
|
end
|
|
296
281
|
|
|
297
|
-
def
|
|
282
|
+
def last_seen_at
|
|
298
283
|
Time.at(Float(@attributes["beat"])) if @attributes["beat"]
|
|
299
284
|
end
|
|
300
285
|
|
|
301
|
-
def quiet
|
|
286
|
+
def quiet
|
|
302
287
|
signal("TSTP")
|
|
303
288
|
end
|
|
304
289
|
|
|
305
|
-
def stop
|
|
290
|
+
def stop
|
|
306
291
|
signal("TERM")
|
|
307
292
|
end
|
|
308
293
|
|
|
@@ -310,22 +295,22 @@ module SolidJobs
|
|
|
310
295
|
signal("TTIN")
|
|
311
296
|
end
|
|
312
297
|
|
|
313
|
-
def
|
|
314
|
-
fields = Array(@config.redis_pool.call("HGETALL",
|
|
315
|
-
fields.each_slice(2).map do |
|
|
316
|
-
|
|
298
|
+
def executions
|
|
299
|
+
fields = Array(@config.redis_pool.call("HGETALL", Keyspace.node_work(identity)))
|
|
300
|
+
fields.each_slice(2).map do |executor_id, raw|
|
|
301
|
+
Execution.new(identity, executor_id, raw)
|
|
317
302
|
end
|
|
318
303
|
end
|
|
319
304
|
|
|
320
305
|
private
|
|
321
306
|
|
|
322
307
|
def signal(name)
|
|
323
|
-
@config.redis_pool.call("LPUSH",
|
|
308
|
+
@config.redis_pool.call("LPUSH", Keyspace.node_signals(identity), name)
|
|
324
309
|
true
|
|
325
310
|
end
|
|
326
311
|
end
|
|
327
312
|
|
|
328
|
-
class
|
|
313
|
+
class Nodes
|
|
329
314
|
include Enumerable
|
|
330
315
|
|
|
331
316
|
def initialize(config: SolidJobs.config)
|
|
@@ -335,44 +320,40 @@ module SolidJobs
|
|
|
335
320
|
def each
|
|
336
321
|
return enum_for(:each) unless block_given?
|
|
337
322
|
|
|
338
|
-
Array(@config.redis_pool.call("SMEMBERS",
|
|
339
|
-
|
|
340
|
-
if
|
|
341
|
-
yield
|
|
323
|
+
Array(@config.redis_pool.call("SMEMBERS", Keyspace::NODES)).each do |identity|
|
|
324
|
+
node = Node.new(identity, config: @config)
|
|
325
|
+
if node.last_seen_at
|
|
326
|
+
yield node
|
|
342
327
|
else
|
|
343
|
-
@config.redis_pool.call("SREM",
|
|
328
|
+
@config.redis_pool.call("SREM", Keyspace::NODES, identity)
|
|
344
329
|
end
|
|
345
330
|
end
|
|
346
331
|
end
|
|
347
|
-
|
|
348
|
-
def size
|
|
349
|
-
count
|
|
350
|
-
end
|
|
351
332
|
end
|
|
352
333
|
|
|
353
|
-
class
|
|
354
|
-
attr_reader :
|
|
334
|
+
class Execution
|
|
335
|
+
attr_reader :node_id, :executor_id
|
|
355
336
|
|
|
356
|
-
def initialize(
|
|
357
|
-
@
|
|
358
|
-
@
|
|
337
|
+
def initialize(node_id, executor_id, raw)
|
|
338
|
+
@node_id = node_id
|
|
339
|
+
@executor_id = executor_id
|
|
359
340
|
@attributes = JSON.parse(raw)
|
|
360
341
|
end
|
|
361
342
|
|
|
362
|
-
def
|
|
363
|
-
@attributes["
|
|
343
|
+
def channel
|
|
344
|
+
@attributes["channel"]
|
|
364
345
|
end
|
|
365
346
|
|
|
366
|
-
def
|
|
367
|
-
@attributes["
|
|
347
|
+
def envelope
|
|
348
|
+
@attributes["envelope"]
|
|
368
349
|
end
|
|
369
350
|
|
|
370
|
-
def
|
|
371
|
-
Time.at(Float(@attributes["
|
|
351
|
+
def started_at
|
|
352
|
+
Time.at(Float(@attributes["started_at"]))
|
|
372
353
|
end
|
|
373
354
|
|
|
374
|
-
def
|
|
375
|
-
@attributes["
|
|
355
|
+
def claim_token
|
|
356
|
+
@attributes["claim_token"]
|
|
376
357
|
end
|
|
377
358
|
|
|
378
359
|
def attempt
|
|
@@ -380,14 +361,14 @@ module SolidJobs
|
|
|
380
361
|
end
|
|
381
362
|
end
|
|
382
363
|
|
|
383
|
-
class
|
|
364
|
+
class ClaimInfo
|
|
384
365
|
attr_reader :attributes
|
|
385
366
|
|
|
386
367
|
def initialize(raw)
|
|
387
368
|
@attributes = JSON.parse(raw)
|
|
388
369
|
end
|
|
389
370
|
|
|
390
|
-
%w[
|
|
371
|
+
%w[task_id claim_token node_id executor_id channel].each do |name|
|
|
391
372
|
define_method(name) { attributes[name] }
|
|
392
373
|
end
|
|
393
374
|
|
|
@@ -395,12 +376,12 @@ module SolidJobs
|
|
|
395
376
|
Integer(attributes["attempt"])
|
|
396
377
|
end
|
|
397
378
|
|
|
398
|
-
def
|
|
399
|
-
Time.at(Float(attributes["
|
|
379
|
+
def claimed_at
|
|
380
|
+
Time.at(Float(attributes["claimed_at"]))
|
|
400
381
|
end
|
|
401
382
|
end
|
|
402
383
|
|
|
403
|
-
class
|
|
384
|
+
class Claims
|
|
404
385
|
include Enumerable
|
|
405
386
|
|
|
406
387
|
def initialize(config: SolidJobs.config)
|
|
@@ -412,13 +393,13 @@ module SolidJobs
|
|
|
412
393
|
|
|
413
394
|
keys.each do |key|
|
|
414
395
|
Array(@config.redis_pool.call("HVALS", key)).each do |raw|
|
|
415
|
-
yield
|
|
396
|
+
yield ClaimInfo.new(raw)
|
|
416
397
|
end
|
|
417
398
|
end
|
|
418
399
|
end
|
|
419
400
|
|
|
420
|
-
def
|
|
421
|
-
find { |
|
|
401
|
+
def find_task(task_id)
|
|
402
|
+
find { |claim| claim.task_id == task_id }
|
|
422
403
|
end
|
|
423
404
|
|
|
424
405
|
private
|
|
@@ -428,7 +409,7 @@ module SolidJobs
|
|
|
428
409
|
found = []
|
|
429
410
|
loop do
|
|
430
411
|
cursor, batch = @config.redis_pool.call(
|
|
431
|
-
"SCAN", cursor, "MATCH", "
|
|
412
|
+
"SCAN", cursor, "MATCH", "#{Keyspace::PREFIX}:node:*:claims", "COUNT", 100,
|
|
432
413
|
)
|
|
433
414
|
found.concat(batch)
|
|
434
415
|
break if cursor == "0"
|
|
@@ -437,21 +418,17 @@ module SolidJobs
|
|
|
437
418
|
end
|
|
438
419
|
end
|
|
439
420
|
|
|
440
|
-
class
|
|
421
|
+
class Executions
|
|
441
422
|
include Enumerable
|
|
442
423
|
|
|
443
424
|
def initialize(config: SolidJobs.config)
|
|
444
|
-
@
|
|
425
|
+
@nodes = Nodes.new(config: config)
|
|
445
426
|
end
|
|
446
427
|
|
|
447
428
|
def each
|
|
448
429
|
return enum_for(:each) unless block_given?
|
|
449
430
|
|
|
450
|
-
@
|
|
451
|
-
end
|
|
452
|
-
|
|
453
|
-
def size
|
|
454
|
-
count
|
|
431
|
+
@nodes.each { |node| node.executions.each { |execution| yield execution } }
|
|
455
432
|
end
|
|
456
433
|
end
|
|
457
434
|
end
|