joblin 0.1.4 → 0.1.5
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/app/models/joblin/background_task/api_access.rb +119 -115
- data/app/models/joblin/background_task/attachments.rb +38 -36
- data/app/models/joblin/background_task/executor.rb +60 -58
- data/app/models/joblin/background_task/options.rb +4 -3
- data/app/models/joblin/background_task/retention_policy.rb +19 -17
- data/app/models/joblin/background_task.rb +8 -4
- data/db/migrate/20250916184852_add_results_to_joblin_background_tasks.rb +6 -0
- data/lib/joblin/version.rb +1 -1
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6cb0e0c2038030615d4e6a50e08aac0166f022a6af89f2a5d157d977e2f03f58
|
|
4
|
+
data.tar.gz: f25744584d54054fe566770b10870159ac9c2a422c8e44cb609aca67116f4c03
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 726db8abb51ae0697aa6299df1179c7ef7a5e7de96681b6da9341d97242d4a39928ca4a274a26d58b35ba519f29c3b7d18b8d19dc4cf66bbdd7f25f0c5f83a2b
|
|
7
|
+
data.tar.gz: 83ca76bd6c338207259f08e4115920613c525c5bbe3be431a6a1299bfc0b79282f69a986ce3c04fa17078b0c2dce24f1de1e8556e8d371bda03bcb7231c5ba15
|
|
@@ -1,155 +1,159 @@
|
|
|
1
1
|
module Joblin
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
aar
|
|
2
|
+
class BackgroundTask
|
|
3
|
+
module ApiAccess
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
class_methods do
|
|
7
|
+
def api_access_rules(&blk)
|
|
8
|
+
@api_access_rules ||= []
|
|
9
|
+
if blk
|
|
10
|
+
@api_access_rules << ApiAccessRules.new.tap do |aar|
|
|
11
|
+
aar.instance_exec(&blk)
|
|
12
|
+
end
|
|
13
|
+
nil
|
|
14
|
+
else
|
|
15
|
+
[*superclass.try(:api_access_rules), *@api_access_rules].compact.freeze
|
|
11
16
|
end
|
|
12
|
-
nil
|
|
13
|
-
else
|
|
14
|
-
[*superclass.try(:api_access_rules), *@api_access_rules].compact.freeze
|
|
15
17
|
end
|
|
16
|
-
end
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
def api_access_allowed?
|
|
25
|
-
# This is intentionally not inherited by subclasses
|
|
26
|
-
@api_access_allowed
|
|
27
|
-
end
|
|
19
|
+
def allow_api_access!(&blk)
|
|
20
|
+
include Mixin unless self < Mixin
|
|
21
|
+
@api_access_allowed = true
|
|
22
|
+
api_access_rules(&blk) if blk
|
|
23
|
+
end
|
|
28
24
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
end
|
|
25
|
+
def api_access_allowed?
|
|
26
|
+
# This is intentionally not inherited by subclasses
|
|
27
|
+
@api_access_allowed
|
|
28
|
+
end
|
|
34
29
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
else
|
|
40
|
-
params ||= controller_or_params
|
|
30
|
+
def find_for_api(id)
|
|
31
|
+
task = find(id)
|
|
32
|
+
raise ActiveRecord::RecordNotFound unless task.api_access_allowed?
|
|
33
|
+
task
|
|
41
34
|
end
|
|
42
35
|
|
|
43
|
-
|
|
44
|
-
|
|
36
|
+
def build_from_api(controller_or_params, options = {}, params: nil, exec_context: nil)
|
|
37
|
+
if controller_or_params.respond_to?(:params)
|
|
38
|
+
exec_context ||= controller_or_params
|
|
39
|
+
params ||= controller_or_params.params.require(:background_task)
|
|
40
|
+
else
|
|
41
|
+
params ||= controller_or_params
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
task_type = self == BackgroundTask ? params[:type].safe_constantize : self
|
|
45
|
+
raise ActiveRecord::RecordNotFound unless task_type && task_type <= BackgroundTask
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
task = task_type.new
|
|
48
|
+
raise ActiveRecord::RecordNotFound unless task.api_access_allowed?
|
|
49
|
+
rule_sets = task_type.api_access_rules
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
51
|
+
# Apply permitted options
|
|
52
|
+
if params[:options].present?
|
|
53
|
+
permitted_options = rule_sets.map(&:permitted_options).flatten
|
|
54
|
+
task.options.merge!(params[:options].permit(permitted_options).to_h)
|
|
55
|
+
end
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
57
|
+
# Apply default options
|
|
58
|
+
rule_sets.reverse.each do |aar|
|
|
59
|
+
aar.default_options.each do |k, v|
|
|
60
|
+
next if task.options.key?(k)
|
|
61
|
+
task.options[k] = v.is_a?(Proc) ? exec_context.instance_exec(&v) : v
|
|
62
|
+
end
|
|
61
63
|
end
|
|
62
|
-
end
|
|
63
64
|
|
|
64
|
-
|
|
65
|
-
|
|
65
|
+
# Apply any additional/hard-coded options
|
|
66
|
+
task.options.merge!(options)
|
|
66
67
|
|
|
67
|
-
|
|
68
|
+
raise ActiveRecord::RecordInvalid.new(task) unless task.api_access_allowed?
|
|
68
69
|
|
|
69
|
-
|
|
70
|
-
|
|
70
|
+
val_errors = task.api_validate_options
|
|
71
|
+
raise ActiveRecord::ValidationError.new(val_errors) unless val_errors.empty?
|
|
71
72
|
|
|
72
|
-
|
|
73
|
+
task
|
|
74
|
+
end
|
|
73
75
|
end
|
|
74
|
-
end
|
|
75
76
|
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
77
|
+
included do
|
|
78
|
+
api_access_rules do
|
|
79
|
+
default_option(:creator) { try(:current_user) }
|
|
80
|
+
end
|
|
79
81
|
end
|
|
80
|
-
end
|
|
81
82
|
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
83
|
+
def api_access_allowed?
|
|
84
|
+
self.class.api_access_allowed?
|
|
85
|
+
end
|
|
85
86
|
|
|
86
|
-
|
|
87
|
-
|
|
87
|
+
module Mixin
|
|
88
|
+
extend ActiveSupport::Concern
|
|
88
89
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
90
|
+
included do
|
|
91
|
+
begin
|
|
92
|
+
::BackgroundTaskChannel
|
|
93
|
+
after_commit do
|
|
94
|
+
::BackgroundTaskChannel.broadcast_to(self, api_serialize) if api_access_allowed?
|
|
95
|
+
end
|
|
96
|
+
rescue NameError
|
|
94
97
|
end
|
|
95
|
-
rescue NameError
|
|
96
98
|
end
|
|
97
|
-
end
|
|
98
99
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
100
|
+
def api_serialize
|
|
101
|
+
builder = Jbuilder.new do |json|
|
|
102
|
+
json.id id
|
|
103
|
+
json.type type
|
|
104
|
+
json.workflow_state workflow_state
|
|
104
105
|
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
106
|
+
json.error_message error_message || "Internal Error" if workflow_state == 'failed'
|
|
107
|
+
|
|
108
|
+
rule_sets = self.class.api_access_rules
|
|
109
|
+
rule_sets.each do |aar|
|
|
110
|
+
instance_exec(json, &aar.serializer) if aar.serializer
|
|
111
|
+
end
|
|
108
112
|
end
|
|
109
|
-
end
|
|
110
113
|
|
|
111
|
-
|
|
112
|
-
|
|
114
|
+
builder.attributes!
|
|
115
|
+
end
|
|
113
116
|
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
117
|
+
def api_validate_options
|
|
118
|
+
errors = []
|
|
119
|
+
rule_sets = self.class.api_access_rules
|
|
120
|
+
rule_sets.each do |aar|
|
|
121
|
+
aar.validators.each do |validator|
|
|
122
|
+
errors << instance_exec(&validator)
|
|
123
|
+
end
|
|
120
124
|
end
|
|
125
|
+
errors.flatten.compact.uniq
|
|
121
126
|
end
|
|
122
|
-
errors.flatten.compact.uniq
|
|
123
127
|
end
|
|
124
|
-
end
|
|
125
128
|
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
129
|
+
class ApiAccessRules
|
|
130
|
+
attr_accessor :serializer
|
|
131
|
+
attr_reader :validators
|
|
132
|
+
attr_reader :default_options
|
|
133
|
+
attr_reader :permitted_options
|
|
134
|
+
|
|
135
|
+
def initialize
|
|
136
|
+
@serializer = nil
|
|
137
|
+
@validators = []
|
|
138
|
+
@permitted_options = []
|
|
139
|
+
@default_options = {}
|
|
140
|
+
end
|
|
138
141
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
+
def default_option(key, value = nil, &blk)
|
|
143
|
+
@default_options[key] = blk || value
|
|
144
|
+
end
|
|
142
145
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
+
def permit_options(*args)
|
|
147
|
+
@permitted_options.concat(args)
|
|
148
|
+
end
|
|
146
149
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
+
def validate(&blk)
|
|
151
|
+
@validators << blk
|
|
152
|
+
end
|
|
150
153
|
|
|
151
|
-
|
|
152
|
-
|
|
154
|
+
def serialize(&blk)
|
|
155
|
+
@serializer = blk
|
|
156
|
+
end
|
|
153
157
|
end
|
|
154
158
|
end
|
|
155
159
|
end
|
|
@@ -1,49 +1,51 @@
|
|
|
1
1
|
module Joblin
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
2
|
+
class BackgroundTask
|
|
3
|
+
module Attachments
|
|
4
|
+
extend ActiveSupport::Concern
|
|
5
|
+
|
|
6
|
+
include Joblin::Concerns::JobWorkingDirs
|
|
7
|
+
|
|
8
|
+
def attachment_path(key, expires_in: true)
|
|
9
|
+
if !expires_in || Rails.env.development? || Rails.env.test?
|
|
10
|
+
return Rails.application.routes.url_helpers.rails_blob_path(
|
|
11
|
+
send(key),
|
|
12
|
+
only_path: true,
|
|
13
|
+
disposition: 'attachment',
|
|
14
|
+
# organization_id: current_organization&.id,
|
|
15
|
+
)
|
|
16
|
+
end
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
if expires_in == true
|
|
19
|
+
send(key).url
|
|
20
|
+
else expires_in
|
|
21
|
+
send(key).url(expires_in:)
|
|
22
|
+
end
|
|
21
23
|
end
|
|
22
|
-
end
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
25
|
+
def attach_file(key, path, as: nil)
|
|
26
|
+
path = File.join(working_dir, path) unless Pathname.new(path).absolute?
|
|
26
27
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
28
|
+
self.send(key).attach(
|
|
29
|
+
io: File.open(path),
|
|
30
|
+
filename: as || File.basename(path)
|
|
31
|
+
)
|
|
32
|
+
end
|
|
32
33
|
|
|
33
|
-
|
|
34
|
-
|
|
34
|
+
def load_attachment(key, save_as: nil)
|
|
35
|
+
@loaded_attachments ||= {}
|
|
35
36
|
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
@loaded_attachments[key] ||= begin
|
|
38
|
+
save_as = save_as || send(key).filename.to_s || key.to_s
|
|
39
|
+
save_as = File.join(working_dir, save_as) unless Pathname.new(save_as).absolute?
|
|
39
40
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
41
|
+
File.open(save_as, 'w') do |file|
|
|
42
|
+
send(key).download do |chunk|
|
|
43
|
+
file.write(chunk.force_encoding("UTF-8"))
|
|
44
|
+
end
|
|
43
45
|
end
|
|
46
|
+
save_as
|
|
44
47
|
end
|
|
45
|
-
save_as
|
|
46
48
|
end
|
|
47
49
|
end
|
|
48
50
|
end
|
|
49
|
-
end
|
|
51
|
+
end
|
|
@@ -1,79 +1,81 @@
|
|
|
1
1
|
module Joblin
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
class BackgroundTask
|
|
3
|
+
module Executor
|
|
4
|
+
extend ActiveSupport::Concern
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
class_methods do
|
|
7
|
+
def inherited(subclass)
|
|
8
|
+
subclass.const_set(:ExecutorJob, Class.new(self::ExecutorJob))
|
|
9
|
+
super
|
|
10
|
+
end
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
def job_executor_class
|
|
13
|
+
self::ExecutorJob
|
|
14
|
+
end
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
def executor_eval(&blk)
|
|
17
|
+
job_executor_class.class_eval(&blk)
|
|
18
|
+
end
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
delegate :queue_as, :sidekiq_options, to: :job_executor_class
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
22
|
+
%i[before around after].each do |hook_type|
|
|
23
|
+
define_method(:"#{hook_type}_perform") do |*args, &callback|
|
|
24
|
+
callback ||= args[0]
|
|
25
|
+
if callback.is_a?(Symbol) || callback.is_a?(String)
|
|
26
|
+
job_executor_class.define_method(callback) do |*margs, &blk|
|
|
27
|
+
the_task.send(callback, *margs, &blk)
|
|
28
|
+
end
|
|
29
|
+
job_executor_class.send(:"#{hook_type}_perform", callback)
|
|
30
|
+
elsif callback.is_a?(Proc)
|
|
31
|
+
# Not exactly pretty...
|
|
32
|
+
proc = case callback.arity
|
|
33
|
+
when 0
|
|
34
|
+
-> { the_task.instance_exec(&callback) }
|
|
35
|
+
when 1
|
|
36
|
+
->(a) { the_task.instance_exec(a, &callback) }
|
|
37
|
+
when 2
|
|
38
|
+
->(a, b) { the_task.instance_exec(a, b, &callback) }
|
|
39
|
+
else
|
|
40
|
+
raise ArgumentError, "Unsupported callback arity #{callback.arity}"
|
|
41
|
+
end
|
|
42
|
+
job_executor_class.send(:"#{hook_type}_perform", &proc)
|
|
40
43
|
end
|
|
41
|
-
job_executor_class.send(:"#{hook_type}_perform", &proc)
|
|
42
44
|
end
|
|
43
45
|
end
|
|
44
|
-
end
|
|
45
|
-
|
|
46
|
-
# delegate :set, to: :job_executor_class
|
|
47
|
-
|
|
48
|
-
# delegate :before_perform, :around_perform, :after_perform, to: :job_executor_class
|
|
49
|
-
# delegate :before_enqueue, :around_enqueue, :after_enqueue, to: :job_executor_class
|
|
50
|
-
end
|
|
51
|
-
|
|
52
|
-
included do
|
|
53
|
-
delegate_missing_to :_current_executor
|
|
54
|
-
end
|
|
55
46
|
|
|
56
|
-
|
|
47
|
+
# delegate :set, to: :job_executor_class
|
|
57
48
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
49
|
+
# delegate :before_perform, :around_perform, :after_perform, to: :job_executor_class
|
|
50
|
+
# delegate :before_enqueue, :around_enqueue, :after_enqueue, to: :job_executor_class
|
|
51
|
+
end
|
|
61
52
|
|
|
62
|
-
|
|
63
|
-
|
|
53
|
+
included do
|
|
54
|
+
delegate_missing_to :_current_executor
|
|
55
|
+
end
|
|
64
56
|
|
|
65
|
-
|
|
66
|
-
the_task.update(workflow_state: "started") if the_task.workflow_state == "scheduled"
|
|
57
|
+
protected
|
|
67
58
|
|
|
68
|
-
|
|
59
|
+
def _current_executor
|
|
60
|
+
@executor
|
|
69
61
|
end
|
|
70
62
|
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
63
|
+
class ExecutorJob < ActiveJob::Base
|
|
64
|
+
def perform
|
|
65
|
+
the_task.update(workflow_state: "started") if the_task.workflow_state == "scheduled"
|
|
66
|
+
the_task.perform
|
|
67
|
+
rescue InvalidJobError => ex
|
|
68
|
+
the_task.error_message ||= ex.message
|
|
69
|
+
the_task.workflow_state = "failed"
|
|
70
|
+
the_task.save! if the_task.changed?
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
def the_task
|
|
74
|
+
@the_task ||= BackgroundTask.find(batch_context[:background_task_id]).tap do |task|
|
|
75
|
+
task.instance_variable_set(:@executor, self)
|
|
76
|
+
end
|
|
74
77
|
end
|
|
75
78
|
end
|
|
76
79
|
end
|
|
77
|
-
|
|
78
80
|
end
|
|
79
81
|
end
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
module
|
|
1
|
+
class Joblin::BackgroundTask
|
|
2
|
+
module Options
|
|
3
3
|
extend ActiveSupport::Concern
|
|
4
4
|
|
|
5
5
|
class_methods do
|
|
@@ -16,7 +16,8 @@ module Joblin
|
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
included do
|
|
19
|
-
serialize :
|
|
19
|
+
serialize :results, coder: Joblin::LazyAccess
|
|
20
|
+
serialize :extra_options, coder: Joblin::LazyAccess
|
|
20
21
|
|
|
21
22
|
after_initialize do
|
|
22
23
|
self.extra_options ||= HashWithIndifferentAccess.new
|
|
@@ -1,26 +1,28 @@
|
|
|
1
1
|
module Joblin
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
class BackgroundTask
|
|
3
|
+
module RetentionPolicy
|
|
4
|
+
extend ActiveSupport::Concern
|
|
4
5
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
class_methods do
|
|
7
|
+
def record_retention(policy = nil)
|
|
8
|
+
if policy.nil?
|
|
9
|
+
@record_retention || superclass.try(:record_retention)
|
|
10
|
+
else
|
|
11
|
+
@record_retention = policy
|
|
12
|
+
end
|
|
11
13
|
end
|
|
12
14
|
end
|
|
13
|
-
end
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
16
|
+
class BackgroundTaskCleaner < ActiveJob::Base
|
|
17
|
+
def perform
|
|
18
|
+
types = BackgroundTask.distinct.pluck(:type)
|
|
19
|
+
types.each do |type|
|
|
20
|
+
type = type.constantize
|
|
21
|
+
rp = type.record_retention
|
|
22
|
+
next unless rp
|
|
22
23
|
|
|
23
|
-
|
|
24
|
+
type.where("created_at < ?", rp.ago).destroy_all
|
|
25
|
+
end
|
|
24
26
|
end
|
|
25
27
|
end
|
|
26
28
|
end
|
|
@@ -6,8 +6,12 @@ module Joblin
|
|
|
6
6
|
include Attachments
|
|
7
7
|
include ApiAccess
|
|
8
8
|
|
|
9
|
+
class InvalidJobError < StandardError; end
|
|
10
|
+
|
|
9
11
|
belongs_to :creator, polymorphic: true, optional: true
|
|
10
12
|
|
|
13
|
+
validates :workflow_state, inclusion: { in: %w[unscheduled scheduled started completed failed cancelled] }
|
|
14
|
+
|
|
11
15
|
after_initialize do
|
|
12
16
|
self.workflow_state ||= 'unscheduled'
|
|
13
17
|
end
|
|
@@ -61,20 +65,20 @@ module Joblin
|
|
|
61
65
|
tracker = BackgroundTask.find(options['id'])
|
|
62
66
|
return if tracker.workflow_state == 'cancelled'
|
|
63
67
|
|
|
64
|
-
tracker.workflow_state
|
|
65
|
-
tracker.save! if tracker.changed?
|
|
68
|
+
# tracker.update!(workflow_state: 'completed') if status.success?
|
|
66
69
|
end
|
|
67
70
|
|
|
68
71
|
def on_success(status, options)
|
|
69
72
|
tracker = BackgroundTask.find(options['id'])
|
|
70
73
|
return if tracker.workflow_state == 'cancelled'
|
|
74
|
+
return if tracker.workflow_state == 'failed'
|
|
71
75
|
|
|
72
|
-
tracker.workflow_state
|
|
73
|
-
tracker.save! if tracker.changed?
|
|
76
|
+
tracker.update!(workflow_state: 'completed')
|
|
74
77
|
end
|
|
75
78
|
|
|
76
79
|
def on_stagnated(status, options)
|
|
77
80
|
tracker = BackgroundTask.find(options['id'])
|
|
81
|
+
tracker.update(workflow_state: 'failed') if tracker.workflow_state != 'cancelled'
|
|
78
82
|
tracker.handle_batch_stagnation
|
|
79
83
|
end
|
|
80
84
|
end
|
data/lib/joblin/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: joblin
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.
|
|
4
|
+
version: 0.1.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ethan Knapp
|
|
@@ -156,6 +156,7 @@ files:
|
|
|
156
156
|
- app/models/joblin/background_task/retention_policy.rb
|
|
157
157
|
- app/models/joblin/concerns/job_working_dirs.rb
|
|
158
158
|
- db/migrate/20250903184852_create_joblin_background_tasks.rb
|
|
159
|
+
- db/migrate/20250916184852_add_results_to_joblin_background_tasks.rb
|
|
159
160
|
- joblin.gemspec
|
|
160
161
|
- lib/joblin.rb
|
|
161
162
|
- lib/joblin/batching/batch.rb
|