operationable 0.2.7 → 0.2.8
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/lib/jobs/operation_job.rb +1 -1
- data/lib/operationable.rb +4 -2
- data/lib/operationable/persisters/base.rb +20 -0
- data/lib/operationable/persisters/database.rb +50 -0
- data/lib/operationable/persisters/memory.rb +134 -0
- data/lib/operationable/runners/base.rb +4 -0
- data/lib/operationable/version.rb +1 -1
- metadata +4 -3
- data/lib/operationable/persister.rb +0 -52
- data/lib/operationable/status.rb +0 -145
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 2acea623e67938b58cb568d705062a86d5005ce2
|
4
|
+
data.tar.gz: 6145faa763a9fe92e19852bf5bb91c2d95c4bb11
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ef5a0e1e38e6978caa2f72d63ec45305ae6d39721957d841d20921459ca310d9018ea8de5a03e472f6dd8fdd7833d15e87c3ddeeb693850513da264e520cce72
|
7
|
+
data.tar.gz: e2bbd17615a9a4285b9be47939d6d73a4386f311f29387e50db200bfa0490724062193c411c5ecec6d65f8c25e442532136acde3bc307ff74e0b1aadd103a8ea
|
data/lib/jobs/operation_job.rb
CHANGED
data/lib/operationable.rb
CHANGED
@@ -12,8 +12,10 @@ require 'operationable/callback'
|
|
12
12
|
require 'operationable/operation'
|
13
13
|
require 'operationable/serializer'
|
14
14
|
require 'operationable/specification'
|
15
|
-
|
16
|
-
require 'operationable/
|
15
|
+
|
16
|
+
require 'operationable/persisters/base'
|
17
|
+
require 'operationable/persisters/database'
|
18
|
+
require 'operationable/persisters/memory'
|
17
19
|
|
18
20
|
require 'operationable/runners/base'
|
19
21
|
require 'operationable/runners/serial'
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Operationable
|
2
|
+
module Persisters
|
3
|
+
module Base
|
4
|
+
STATUS_INIT = 'init'
|
5
|
+
STATUS_QUEUED = 'queued'
|
6
|
+
STATUS_WORKING = 'working'
|
7
|
+
STATUS_COMPLETED = 'completed'
|
8
|
+
STATUS_FAILED = 'failed'
|
9
|
+
STATUS_KILLED = 'killed'
|
10
|
+
STATUSES = [
|
11
|
+
STATUS_INIT,
|
12
|
+
STATUS_QUEUED,
|
13
|
+
STATUS_WORKING,
|
14
|
+
STATUS_COMPLETED,
|
15
|
+
STATUS_FAILED,
|
16
|
+
STATUS_KILLED
|
17
|
+
].freeze
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
module Operationable
|
3
|
+
module Persisters
|
4
|
+
module Database
|
5
|
+
class << self
|
6
|
+
def persist(callbacks, initiator_id, params, name)
|
7
|
+
::Operation.create(
|
8
|
+
callbacks: callbacks.map { |callback|
|
9
|
+
{
|
10
|
+
status: Operationable::Persisters::Base::STATUS_INIT,
|
11
|
+
name: callback[:callback_method_name],
|
12
|
+
queue: callback[:queue]
|
13
|
+
}
|
14
|
+
},
|
15
|
+
initiator_id: initiator_id,
|
16
|
+
params: params,
|
17
|
+
name: name
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
def working(id, name)
|
22
|
+
update(id, name, Operationable::Persisters::Base::STATUS_WORKING)
|
23
|
+
end
|
24
|
+
|
25
|
+
def completed(id, name)
|
26
|
+
update(id, name, Operationable::Persisters::Base::STATUS_COMPLETED)
|
27
|
+
end
|
28
|
+
|
29
|
+
def around_call(id, name, block)
|
30
|
+
working(id, name)
|
31
|
+
block.call
|
32
|
+
completed(id, name)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
def update(id, name, status)
|
38
|
+
op = ::Operation.find(id)
|
39
|
+
callbacks = op.callbacks.map do |cb|
|
40
|
+
cb['status'] = status if cb['name'] === name
|
41
|
+
cb
|
42
|
+
end
|
43
|
+
|
44
|
+
op.callbacks = callbacks
|
45
|
+
op.save
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,134 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# codebase has been taken from abandoned resque-status gem, that not compatible with ActiveJob and Rails now
|
3
|
+
module Operationable
|
4
|
+
module Persisters
|
5
|
+
module Memory
|
6
|
+
extend Forwardable
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
autoload :Hash, 'resque/plugins/status/hash'
|
10
|
+
|
11
|
+
# The error class raised when a job is killed
|
12
|
+
class Killed < RuntimeError; end
|
13
|
+
class NotANumber < RuntimeError; end
|
14
|
+
|
15
|
+
attr_reader :uuid, :options
|
16
|
+
|
17
|
+
def create_status_hash(job)
|
18
|
+
Resque::Plugins::Status::Hash.create(self.job_id, arguments.first)
|
19
|
+
end
|
20
|
+
|
21
|
+
def uuid
|
22
|
+
self.job_id
|
23
|
+
end
|
24
|
+
|
25
|
+
def options
|
26
|
+
arguments.first
|
27
|
+
end
|
28
|
+
|
29
|
+
# Run by the Resque::Worker when processing this job. It wraps the <tt>perform</tt>
|
30
|
+
# method ensuring that the final status of the job is set regardless of error.
|
31
|
+
# If an error occurs within the job's work, it will set the status as failed and
|
32
|
+
# re-raise the error.
|
33
|
+
def safe_perform(job, block)
|
34
|
+
working
|
35
|
+
|
36
|
+
block.call
|
37
|
+
|
38
|
+
if status && status.failed?
|
39
|
+
on_failure(status.message) if respond_to?(:on_failure)
|
40
|
+
return
|
41
|
+
elsif status && !status.completed?
|
42
|
+
completed
|
43
|
+
end
|
44
|
+
on_success if respond_to?(:on_success)
|
45
|
+
rescue Killed
|
46
|
+
Resque::Plugins::Status::Hash.killed(uuid)
|
47
|
+
on_killed if respond_to?(:on_killed)
|
48
|
+
rescue => e
|
49
|
+
failed("The task failed because of an error: #{e}")
|
50
|
+
if respond_to?(:on_failure)
|
51
|
+
on_failure(e)
|
52
|
+
else
|
53
|
+
raise e
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
# Set the jobs status. Can take an array of strings or hashes that are merged
|
58
|
+
# (in order) into a final status hash.
|
59
|
+
def status=(new_status)
|
60
|
+
Resque::Plugins::Status::Hash.set(uuid, *new_status)
|
61
|
+
end
|
62
|
+
|
63
|
+
# get the Resque::Plugins::Status::Hash object for the current uuid
|
64
|
+
def status
|
65
|
+
Resque::Plugins::Status::Hash.get(uuid)
|
66
|
+
end
|
67
|
+
|
68
|
+
def name
|
69
|
+
"#{self.class.name}(#{options.inspect unless options.empty?})"
|
70
|
+
end
|
71
|
+
|
72
|
+
# Checks against the kill list if this specific job instance should be killed
|
73
|
+
# on the next iteration
|
74
|
+
def should_kill?
|
75
|
+
Resque::Plugins::Status::Hash.should_kill?(uuid)
|
76
|
+
end
|
77
|
+
|
78
|
+
# set the status of the job for the current itteration. <tt>num</tt> and
|
79
|
+
# <tt>total</tt> are passed to the status as well as any messages.
|
80
|
+
# This will kill the job if it has been added to the kill list with
|
81
|
+
# <tt>Resque::Plugins::Status::Hash.kill()</tt>
|
82
|
+
def at(num, total, *messages)
|
83
|
+
if total.to_f <= 0.0
|
84
|
+
raise(NotANumber, "Called at() with total=#{total} which is not a number")
|
85
|
+
end
|
86
|
+
tick({
|
87
|
+
'num' => num,
|
88
|
+
'total' => total
|
89
|
+
}, *messages)
|
90
|
+
end
|
91
|
+
|
92
|
+
def working
|
93
|
+
set_status({'status' => Operationable::Persisters::Base::STATUS_WORKING})
|
94
|
+
end
|
95
|
+
|
96
|
+
# sets the status of the job for the current itteration. You should use
|
97
|
+
# the <tt>at</tt> method if you have actual numbers to track the iteration count.
|
98
|
+
# This will kill the job if it has been added to the kill list with
|
99
|
+
# <tt>Resque::Plugins::Status::Hash.kill()</tt>
|
100
|
+
def tick(*messages)
|
101
|
+
kill! if should_kill?
|
102
|
+
set_status({'status' => Operationable::Persisters::Base::STATUS_WORKING}, *messages)
|
103
|
+
end
|
104
|
+
|
105
|
+
# set the status to 'failed' passing along any additional messages
|
106
|
+
def failed(*messages)
|
107
|
+
set_status({'status' => Operationable::Persisters::Base::STATUS_FAILED}, *messages)
|
108
|
+
end
|
109
|
+
|
110
|
+
# set the status to 'completed' passing along any addional messages
|
111
|
+
def completed(*messages)
|
112
|
+
set_status({
|
113
|
+
'status' => Operationable::Persisters::Base::STATUS_COMPLETED,
|
114
|
+
'message' => "Completed at #{Time.now}"
|
115
|
+
}, *messages)
|
116
|
+
end
|
117
|
+
|
118
|
+
# kill the current job, setting the status to 'killed' and raising <tt>Killed</tt>
|
119
|
+
def kill!
|
120
|
+
set_status({
|
121
|
+
'status' => Operationable::Persisters::Base::STATUS_KILLED,
|
122
|
+
'message' => "Killed at #{Time.now}"
|
123
|
+
})
|
124
|
+
raise Killed
|
125
|
+
end
|
126
|
+
|
127
|
+
private
|
128
|
+
|
129
|
+
def set_status(*args)
|
130
|
+
self.status = [status, {'name' => self.name}, args].flatten
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: operationable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kirill Suhodolov
|
@@ -119,13 +119,14 @@ files:
|
|
119
119
|
- lib/operationable/builder.rb
|
120
120
|
- lib/operationable/callback.rb
|
121
121
|
- lib/operationable/operation.rb
|
122
|
-
- lib/operationable/
|
122
|
+
- lib/operationable/persisters/base.rb
|
123
|
+
- lib/operationable/persisters/database.rb
|
124
|
+
- lib/operationable/persisters/memory.rb
|
123
125
|
- lib/operationable/runners/base.rb
|
124
126
|
- lib/operationable/runners/separate.rb
|
125
127
|
- lib/operationable/runners/serial.rb
|
126
128
|
- lib/operationable/serializer.rb
|
127
129
|
- lib/operationable/specification.rb
|
128
|
-
- lib/operationable/status.rb
|
129
130
|
- lib/operationable/version.rb
|
130
131
|
- lib/operations/create.rb
|
131
132
|
- lib/operations/destroy.rb
|
@@ -1,52 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
module Operationable
|
3
|
-
module Persister
|
4
|
-
def persist_operation
|
5
|
-
@persist_operation ||= ::Operationable::Persister.persist(check_callbacks, user.id, props, operation_class_name)
|
6
|
-
end
|
7
|
-
|
8
|
-
class << self
|
9
|
-
def persist(callbacks, initiator_id, params, name)
|
10
|
-
::Operation.create(
|
11
|
-
callbacks: callbacks.map { |callback|
|
12
|
-
{
|
13
|
-
status: ::Operation::STATUS_INIT,
|
14
|
-
name: callback[:callback_method_name],
|
15
|
-
queue: callback[:queue]
|
16
|
-
}
|
17
|
-
},
|
18
|
-
initiator_id: initiator_id,
|
19
|
-
params: params,
|
20
|
-
name: name
|
21
|
-
)
|
22
|
-
end
|
23
|
-
|
24
|
-
def working(id, name)
|
25
|
-
update(id, name, ::Operation::STATUS_WORKING)
|
26
|
-
end
|
27
|
-
|
28
|
-
def completed(id, name)
|
29
|
-
update(id, name, ::Operation::STATUS_COMPLETED)
|
30
|
-
end
|
31
|
-
|
32
|
-
def around_call(id, name, block)
|
33
|
-
working(id, name)
|
34
|
-
block.call
|
35
|
-
completed(id, name)
|
36
|
-
end
|
37
|
-
|
38
|
-
private
|
39
|
-
|
40
|
-
def update(id, name, status)
|
41
|
-
op = ::Operation.find(id)
|
42
|
-
callbacks = op.callbacks.map do |cb|
|
43
|
-
cb['status'] = status if cb['name'] === name
|
44
|
-
cb
|
45
|
-
end
|
46
|
-
|
47
|
-
op.callbacks = callbacks
|
48
|
-
op.save
|
49
|
-
end
|
50
|
-
end
|
51
|
-
end
|
52
|
-
end
|
data/lib/operationable/status.rb
DELETED
@@ -1,145 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
# codebase has been taken from abandoned resque-status gem, that not compatible with ActiveJob and Rails now
|
3
|
-
module Operationable
|
4
|
-
module Status
|
5
|
-
extend Forwardable
|
6
|
-
extend ActiveSupport::Concern
|
7
|
-
|
8
|
-
STATUS_QUEUED = 'queued'
|
9
|
-
STATUS_WORKING = 'working'
|
10
|
-
STATUS_COMPLETED = 'completed'
|
11
|
-
STATUS_FAILED = 'failed'
|
12
|
-
STATUS_KILLED = 'killed'
|
13
|
-
STATUSES = [
|
14
|
-
STATUS_QUEUED,
|
15
|
-
STATUS_WORKING,
|
16
|
-
STATUS_COMPLETED,
|
17
|
-
STATUS_FAILED,
|
18
|
-
STATUS_KILLED
|
19
|
-
].freeze
|
20
|
-
|
21
|
-
autoload :Hash, 'resque/plugins/status/hash'
|
22
|
-
|
23
|
-
# The error class raised when a job is killed
|
24
|
-
class Killed < RuntimeError; end
|
25
|
-
class NotANumber < RuntimeError; end
|
26
|
-
|
27
|
-
attr_reader :uuid, :options
|
28
|
-
|
29
|
-
def create_status_hash(job)
|
30
|
-
Resque::Plugins::Status::Hash.create(self.job_id, arguments.first)
|
31
|
-
end
|
32
|
-
|
33
|
-
def uuid
|
34
|
-
self.job_id
|
35
|
-
end
|
36
|
-
|
37
|
-
def options
|
38
|
-
arguments.first
|
39
|
-
end
|
40
|
-
|
41
|
-
# Run by the Resque::Worker when processing this job. It wraps the <tt>perform</tt>
|
42
|
-
# method ensuring that the final status of the job is set regardless of error.
|
43
|
-
# If an error occurs within the job's work, it will set the status as failed and
|
44
|
-
# re-raise the error.
|
45
|
-
def safe_perform(job, block)
|
46
|
-
working
|
47
|
-
|
48
|
-
block.call
|
49
|
-
|
50
|
-
if status && status.failed?
|
51
|
-
on_failure(status.message) if respond_to?(:on_failure)
|
52
|
-
return
|
53
|
-
elsif status && !status.completed?
|
54
|
-
completed
|
55
|
-
end
|
56
|
-
on_success if respond_to?(:on_success)
|
57
|
-
rescue Killed
|
58
|
-
Resque::Plugins::Status::Hash.killed(uuid)
|
59
|
-
on_killed if respond_to?(:on_killed)
|
60
|
-
rescue => e
|
61
|
-
failed("The task failed because of an error: #{e}")
|
62
|
-
if respond_to?(:on_failure)
|
63
|
-
on_failure(e)
|
64
|
-
else
|
65
|
-
raise e
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
# Set the jobs status. Can take an array of strings or hashes that are merged
|
70
|
-
# (in order) into a final status hash.
|
71
|
-
def status=(new_status)
|
72
|
-
Resque::Plugins::Status::Hash.set(uuid, *new_status)
|
73
|
-
end
|
74
|
-
|
75
|
-
# get the Resque::Plugins::Status::Hash object for the current uuid
|
76
|
-
def status
|
77
|
-
Resque::Plugins::Status::Hash.get(uuid)
|
78
|
-
end
|
79
|
-
|
80
|
-
def name
|
81
|
-
"#{self.class.name}(#{options.inspect unless options.empty?})"
|
82
|
-
end
|
83
|
-
|
84
|
-
# Checks against the kill list if this specific job instance should be killed
|
85
|
-
# on the next iteration
|
86
|
-
def should_kill?
|
87
|
-
Resque::Plugins::Status::Hash.should_kill?(uuid)
|
88
|
-
end
|
89
|
-
|
90
|
-
# set the status of the job for the current itteration. <tt>num</tt> and
|
91
|
-
# <tt>total</tt> are passed to the status as well as any messages.
|
92
|
-
# This will kill the job if it has been added to the kill list with
|
93
|
-
# <tt>Resque::Plugins::Status::Hash.kill()</tt>
|
94
|
-
def at(num, total, *messages)
|
95
|
-
if total.to_f <= 0.0
|
96
|
-
raise(NotANumber, "Called at() with total=#{total} which is not a number")
|
97
|
-
end
|
98
|
-
tick({
|
99
|
-
'num' => num,
|
100
|
-
'total' => total
|
101
|
-
}, *messages)
|
102
|
-
end
|
103
|
-
|
104
|
-
def working
|
105
|
-
set_status({'status' => STATUS_WORKING})
|
106
|
-
end
|
107
|
-
|
108
|
-
# sets the status of the job for the current itteration. You should use
|
109
|
-
# the <tt>at</tt> method if you have actual numbers to track the iteration count.
|
110
|
-
# This will kill the job if it has been added to the kill list with
|
111
|
-
# <tt>Resque::Plugins::Status::Hash.kill()</tt>
|
112
|
-
def tick(*messages)
|
113
|
-
kill! if should_kill?
|
114
|
-
set_status({'status' => STATUS_WORKING}, *messages)
|
115
|
-
end
|
116
|
-
|
117
|
-
# set the status to 'failed' passing along any additional messages
|
118
|
-
def failed(*messages)
|
119
|
-
set_status({'status' => STATUS_FAILED}, *messages)
|
120
|
-
end
|
121
|
-
|
122
|
-
# set the status to 'completed' passing along any addional messages
|
123
|
-
def completed(*messages)
|
124
|
-
set_status({
|
125
|
-
'status' => STATUS_COMPLETED,
|
126
|
-
'message' => "Completed at #{Time.now}"
|
127
|
-
}, *messages)
|
128
|
-
end
|
129
|
-
|
130
|
-
# kill the current job, setting the status to 'killed' and raising <tt>Killed</tt>
|
131
|
-
def kill!
|
132
|
-
set_status({
|
133
|
-
'status' => STATUS_KILLED,
|
134
|
-
'message' => "Killed at #{Time.now}"
|
135
|
-
})
|
136
|
-
raise Killed
|
137
|
-
end
|
138
|
-
|
139
|
-
private
|
140
|
-
|
141
|
-
def set_status(*args)
|
142
|
-
self.status = [status, {'name' => self.name}, args].flatten
|
143
|
-
end
|
144
|
-
end
|
145
|
-
end
|