bricolage 5.30.0 → 6.0.0beta5
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/.gitignore +1 -3
- data/.ruby-version +1 -0
- data/README.md +3 -0
- data/RELEASE.md +22 -0
- data/Rakefile +11 -1
- data/bricolage.gemspec +9 -7
- data/config/test/datasource.yml +9 -0
- data/jobclass/rebuild-rename.rb +7 -7
- data/jobclass/streaming_load.rb +3 -3
- data/lib/bricolage/application.rb +5 -5
- data/lib/bricolage/configloader.rb +1 -1
- data/lib/bricolage/context.rb +18 -11
- data/lib/bricolage/dao/job.rb +184 -0
- data/lib/bricolage/dao/jobexecution.rb +253 -0
- data/lib/bricolage/dao/jobnet.rb +158 -0
- data/lib/bricolage/datasource.rb +1 -1
- data/lib/bricolage/exception.rb +11 -0
- data/lib/bricolage/filedatasource.rb +1 -1
- data/lib/bricolage/genericdatasource.rb +1 -2
- data/lib/bricolage/job.rb +14 -9
- data/lib/bricolage/jobnet.rb +9 -6
- data/lib/bricolage/jobnetrunner.rb +82 -45
- data/lib/bricolage/logger.rb +3 -3
- data/lib/bricolage/loglocator.rb +19 -1
- data/lib/bricolage/postgresconnection.rb +6 -4
- data/lib/bricolage/psqldatasource.rb +74 -5
- data/lib/bricolage/rubyjobclass.rb +1 -2
- data/lib/bricolage/sqlutils.rb +43 -1
- data/lib/bricolage/taskqueue.rb +221 -63
- data/lib/bricolage/vacuumlock.rb +2 -2
- data/lib/bricolage/version.rb +1 -1
- data/schema/Dockerfile +16 -0
- data/schema/Gemfile +5 -0
- data/schema/Gemfile.lock +38 -0
- data/schema/Schemafile +57 -0
- data/schema/database.yml +8 -0
- data/schema/ridgepole_dryrun.sh +2 -0
- data/schema/ridgepole_merge.sh +2 -0
- metadata +65 -25
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 97c5b2453966ea1464172b34c23e7ba3e6f44c715d745f17f07ebbddf361c437
|
|
4
|
+
data.tar.gz: 6044bb40e6dabedd831dc90dd4f61e8fc6614bd4b0885233ba2362b1e1c051b8
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 421dd79e8da48871f3a6694f4ca8bc490280acd4dfad11f10c3165854e7c6a33b76b374a5939805304d2b53307c40c048c28c266f57b54514bf9d81226c21304
|
|
7
|
+
data.tar.gz: 95c5f97fdf7851d6def0e87713acf3eaae136ba8d2e5971b85b10cbd7b04b95f41e28925eac4912f63d2359e818e94d09c3fa905c8947e9b38747c2c71417f08
|
data/.gitignore
CHANGED
data/.ruby-version
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
3.0
|
data/README.md
CHANGED
data/RELEASE.md
CHANGED
|
@@ -1,5 +1,27 @@
|
|
|
1
1
|
# Bricolage Release Note
|
|
2
2
|
|
|
3
|
+
## version 6.0.0 beta 5
|
|
4
|
+
|
|
5
|
+
- [new] Supports Ruby 3.0.
|
|
6
|
+
|
|
7
|
+
## version 6.0.0 beta 4
|
|
8
|
+
|
|
9
|
+
- [fix] rebuild-rename did not work with ALTER RENAME syntax error.
|
|
10
|
+
|
|
11
|
+
## version 6.0.0 beta 3
|
|
12
|
+
|
|
13
|
+
- [new] Upgrades pg from 0.18 to 1.2.
|
|
14
|
+
|
|
15
|
+
## version 6.0.0 beta 2
|
|
16
|
+
|
|
17
|
+
- [fix] Always transmit error messages from jobs in the jobnet.
|
|
18
|
+
|
|
19
|
+
## version 6.0.0 beta 1
|
|
20
|
+
|
|
21
|
+
- [new] Introduces database queue. Database queue saves job states in the PostgreSQL instance, we now can run bricolage on container environment.
|
|
22
|
+
- [new] Default log level is DEBUG on development environment, INFO on production environment.
|
|
23
|
+
- [new] Only updating query is logged as INFO level. Read-only queries are logged in DEBUG level.
|
|
24
|
+
|
|
3
25
|
## version 5.30.0
|
|
4
26
|
|
|
5
27
|
- [new] streaming_load: new option --ctl-ds to change S3 data source for metadata files.
|
data/Rakefile
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
require 'rake/testtask'
|
|
2
|
+
|
|
1
3
|
task :test do
|
|
2
|
-
|
|
4
|
+
desc 'Run tests'
|
|
5
|
+
Rake::TestTask.new do |t|
|
|
6
|
+
# To run test cases of specific file(s), Use:
|
|
7
|
+
# % rake test TEST=test/test_specified_path.rb
|
|
8
|
+
t.libs << "test"
|
|
9
|
+
t.test_files = Dir["test/**/test_*.rb"]
|
|
10
|
+
t.verbose = true
|
|
11
|
+
t.warning = true
|
|
12
|
+
end
|
|
3
13
|
end
|
data/bricolage.gemspec
CHANGED
|
@@ -16,11 +16,13 @@ Gem::Specification.new do |s|
|
|
|
16
16
|
s.executables = s.files.grep(%r{bin/}).map {|path| File.basename(path) }
|
|
17
17
|
s.require_path = 'lib'
|
|
18
18
|
|
|
19
|
-
s.required_ruby_version = '>= 2.
|
|
20
|
-
s.add_dependency 'pg', '~>
|
|
21
|
-
s.add_dependency 'aws-sdk-s3', '~> 1'
|
|
22
|
-
s.add_dependency 'aws-sdk-sns', '~> 1'
|
|
23
|
-
s.
|
|
24
|
-
s.add_development_dependency '
|
|
25
|
-
s.add_development_dependency '
|
|
19
|
+
s.required_ruby_version = '>= 2.4.0'
|
|
20
|
+
s.add_dependency 'pg', '~> 1.2.3'
|
|
21
|
+
s.add_dependency 'aws-sdk-s3', '~> 1.64'
|
|
22
|
+
s.add_dependency 'aws-sdk-sns', '~> 1.23'
|
|
23
|
+
s.add_dependency 'nokogiri' # aws-sdk-core requires this
|
|
24
|
+
s.add_development_dependency 'test-unit', '~> 3.3'
|
|
25
|
+
s.add_development_dependency 'rake', '~> 13.0'
|
|
26
|
+
s.add_development_dependency 'mocha', '~> 1.11'
|
|
27
|
+
s.add_development_dependency 'pry-byebug', '~> 3.9'
|
|
26
28
|
end
|
data/jobclass/rebuild-rename.rb
CHANGED
|
@@ -21,18 +21,18 @@ JobClass.define('rebuild-rename') {
|
|
|
21
21
|
|
|
22
22
|
script {|params, script|
|
|
23
23
|
script.task(params['data-source']) {|task|
|
|
24
|
-
dest_table = '
|
|
25
|
-
prev_table =
|
|
26
|
-
work_table =
|
|
24
|
+
dest_table = params['dest-table']
|
|
25
|
+
prev_table = TableSpec.parse("#{dest_table}_old")
|
|
26
|
+
work_table = TableSpec.parse("#{dest_table}_wk")
|
|
27
27
|
|
|
28
28
|
task.transaction {
|
|
29
29
|
# CREATE
|
|
30
30
|
task.drop_force prev_table
|
|
31
31
|
task.drop_force work_table
|
|
32
|
-
task.exec params['table-def'].replace(/\$\{?dest_table\}?\b/, work_table)
|
|
32
|
+
task.exec params['table-def'].replace(/\$\{?dest_table\}?\b/, work_table.to_s)
|
|
33
33
|
|
|
34
34
|
# INSERT
|
|
35
|
-
task.exec params['sql-file'].replace(/\$\{?dest_table\}?\b/, work_table)
|
|
35
|
+
task.exec params['sql-file'].replace(/\$\{?dest_table\}?\b/, work_table.to_s)
|
|
36
36
|
|
|
37
37
|
# GRANT
|
|
38
38
|
task.grant_if params['grant'], work_table
|
|
@@ -45,8 +45,8 @@ JobClass.define('rebuild-rename') {
|
|
|
45
45
|
# RENAME
|
|
46
46
|
task.transaction {
|
|
47
47
|
task.create_dummy_table dest_table
|
|
48
|
-
task.rename_table dest_table, prev_table
|
|
49
|
-
task.rename_table work_table, dest_table
|
|
48
|
+
task.rename_table dest_table, prev_table.name
|
|
49
|
+
task.rename_table work_table, dest_table.name
|
|
50
50
|
}
|
|
51
51
|
}
|
|
52
52
|
}
|
data/jobclass/streaming_load.rb
CHANGED
|
@@ -144,7 +144,7 @@ class StreamingLoadJobClass < RubyJobClass
|
|
|
144
144
|
@ds.open {|conn|
|
|
145
145
|
execute_update conn, "delete #{log_table_wk};"
|
|
146
146
|
execute_update conn, load_log_copy_stmt(log_table_wk, log_url, @src.credential_string)
|
|
147
|
-
loaded,
|
|
147
|
+
loaded, _not_loaded = partition_loaded_objects(conn, objects, log_table_wk)
|
|
148
148
|
loaded.each do |obj|
|
|
149
149
|
obj.dequeue(force: true, noop: @noop)
|
|
150
150
|
end
|
|
@@ -212,7 +212,7 @@ class StreamingLoadJobClass < RubyJobClass
|
|
|
212
212
|
end
|
|
213
213
|
@logger.info "creating manifest: #{manifest_name}"
|
|
214
214
|
json = make_manifest_json(objects)
|
|
215
|
-
@logger.
|
|
215
|
+
@logger.debug "manifest:\n" + json
|
|
216
216
|
url = @src.put_control_file(manifest_name, json, noop: @noop)
|
|
217
217
|
yield url
|
|
218
218
|
@src.remove_control_file(File.basename(url), noop: @noop) unless @keep_ctl
|
|
@@ -241,7 +241,7 @@ class StreamingLoadJobClass < RubyJobClass
|
|
|
241
241
|
log_name = "load_log-#{@job_process_id}.csv"
|
|
242
242
|
@logger.info "creating tmp load log: #{log_name}"
|
|
243
243
|
csv = make_load_log_csv(objects)
|
|
244
|
-
@logger.
|
|
244
|
+
@logger.debug "load_log:\n" + csv
|
|
245
245
|
url = @src.put_control_file(log_name, csv, noop: @noop)
|
|
246
246
|
begin
|
|
247
247
|
yield url
|
|
@@ -39,7 +39,7 @@ module Bricolage
|
|
|
39
39
|
@hooks.run_before_option_parsing_hooks(opts)
|
|
40
40
|
opts.parse!(ARGV)
|
|
41
41
|
|
|
42
|
-
@ctx = Context.for_application(opts.home, opts.job_file, environment: opts.environment,
|
|
42
|
+
@ctx = Context.for_application(opts.home, opts.job_file, environment: opts.environment, option_variables: opts.option_variables)
|
|
43
43
|
opts.merge_saved_options(@ctx.load_system_options)
|
|
44
44
|
|
|
45
45
|
if opts.dump_options?
|
|
@@ -294,7 +294,7 @@ module Bricolage
|
|
|
294
294
|
@job_file = nil
|
|
295
295
|
@environment = nil
|
|
296
296
|
@home = nil
|
|
297
|
-
@
|
|
297
|
+
@option_variables = Variables.new
|
|
298
298
|
@dry_run = false
|
|
299
299
|
@explain = false
|
|
300
300
|
@list_global_variables = false
|
|
@@ -351,9 +351,9 @@ Global Options:
|
|
|
351
351
|
parser.on('-r', '--require=FEATURE', 'Requires ruby library.') {|feature|
|
|
352
352
|
require feature
|
|
353
353
|
}
|
|
354
|
-
parser.on('-v', '--variable=NAME=VALUE', 'Set
|
|
354
|
+
parser.on('-v', '--variable=NAME=VALUE', 'Set option variable.') {|name_value|
|
|
355
355
|
name, value = name_value.split('=', 2)
|
|
356
|
-
@
|
|
356
|
+
@option_variables[name] = value
|
|
357
357
|
}
|
|
358
358
|
parser.on('--dump-options', 'Shows option parsing result and quit.') {
|
|
359
359
|
@dump_options = true
|
|
@@ -401,7 +401,7 @@ Global Options:
|
|
|
401
401
|
@dump_options
|
|
402
402
|
end
|
|
403
403
|
|
|
404
|
-
attr_reader :
|
|
404
|
+
attr_reader :option_variables
|
|
405
405
|
|
|
406
406
|
def list_global_variables?
|
|
407
407
|
@list_global_variables
|
data/lib/bricolage/context.rb
CHANGED
|
@@ -19,7 +19,7 @@ module Bricolage
|
|
|
19
19
|
FileSystem.home_path(opt_path)
|
|
20
20
|
end
|
|
21
21
|
|
|
22
|
-
def Context.for_application(home_path = nil, job_path_0 = nil, job_path: nil, environment: nil,
|
|
22
|
+
def Context.for_application(home_path = nil, job_path_0 = nil, job_path: nil, environment: nil, option_variables: nil, logger: nil)
|
|
23
23
|
env = environment(environment)
|
|
24
24
|
if (job_path ||= job_path_0)
|
|
25
25
|
fs = FileSystem.for_job_path(job_path, env)
|
|
@@ -29,24 +29,28 @@ module Bricolage
|
|
|
29
29
|
else
|
|
30
30
|
fs = FileSystem.for_options(home_path, env)
|
|
31
31
|
end
|
|
32
|
-
load(fs, env,
|
|
32
|
+
load(fs, env, option_variables: option_variables, logger: logger)
|
|
33
33
|
end
|
|
34
34
|
|
|
35
|
-
def Context.load(fs, env,
|
|
36
|
-
new(fs, env,
|
|
35
|
+
def Context.load(fs, env, option_variables: nil, data_sources: nil, logger: nil)
|
|
36
|
+
new(fs, env, option_variables: option_variables, logger: logger).tap {|ctx|
|
|
37
37
|
ctx.load_configurations
|
|
38
38
|
}
|
|
39
39
|
end
|
|
40
40
|
private_class_method :load
|
|
41
41
|
|
|
42
|
-
def initialize(fs, env,
|
|
43
|
-
@logger = logger ||
|
|
42
|
+
def initialize(fs, env, option_variables: nil, data_sources: nil, logger: nil)
|
|
43
|
+
@logger = logger || default_logger(env)
|
|
44
44
|
@filesystem = fs
|
|
45
45
|
@environment = env
|
|
46
|
-
@
|
|
46
|
+
@option_variables = option_variables || Variables.new
|
|
47
47
|
@data_sources = data_sources
|
|
48
48
|
end
|
|
49
49
|
|
|
50
|
+
private def default_logger(env)
|
|
51
|
+
Logger.new(device: $stderr, level: Logger::INFO)
|
|
52
|
+
end
|
|
53
|
+
|
|
50
54
|
def load_configurations
|
|
51
55
|
@filesystem.config_pathes('prelude.rb').each do |path|
|
|
52
56
|
EmbeddedCodeAPI.module_eval(File.read(path), path.to_s, 1) if path.exist?
|
|
@@ -56,6 +60,7 @@ module Bricolage
|
|
|
56
60
|
|
|
57
61
|
attr_reader :environment
|
|
58
62
|
attr_reader :logger
|
|
63
|
+
attr_reader :option_variables
|
|
59
64
|
|
|
60
65
|
def get_data_source(type, name)
|
|
61
66
|
@data_sources.get(type, name)
|
|
@@ -63,7 +68,7 @@ module Bricolage
|
|
|
63
68
|
|
|
64
69
|
def subsystem(id)
|
|
65
70
|
self.class.new(@filesystem.subsystem(id), @environment,
|
|
66
|
-
|
|
71
|
+
option_variables: @option_variables,
|
|
67
72
|
data_sources: @data_sources,
|
|
68
73
|
logger: @logger)
|
|
69
74
|
end
|
|
@@ -102,7 +107,6 @@ module Bricolage
|
|
|
102
107
|
Variables.union(
|
|
103
108
|
builtin_variables,
|
|
104
109
|
load_global_variables,
|
|
105
|
-
@opt_global_variables
|
|
106
110
|
)
|
|
107
111
|
end
|
|
108
112
|
|
|
@@ -130,8 +134,11 @@ module Bricolage
|
|
|
130
134
|
|
|
131
135
|
def load_variables(path)
|
|
132
136
|
Variables.define {|vars|
|
|
133
|
-
@filesystem.config_file_loader.load_yaml(path)
|
|
134
|
-
|
|
137
|
+
kvs = @filesystem.config_file_loader.load_yaml(path)
|
|
138
|
+
if kvs
|
|
139
|
+
kvs.each do |name, value|
|
|
140
|
+
vars[name] = value
|
|
141
|
+
end
|
|
135
142
|
end
|
|
136
143
|
}
|
|
137
144
|
end
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
require 'bricolage/exception'
|
|
2
|
+
|
|
3
|
+
module Bricolage
|
|
4
|
+
module DAO
|
|
5
|
+
|
|
6
|
+
class Job
|
|
7
|
+
include SQLUtils
|
|
8
|
+
|
|
9
|
+
Attributes = Struct.new(:id, :subsystem, :job_name, :jobnet_id, :executor_id, keyword_init: true)
|
|
10
|
+
|
|
11
|
+
def Job.for_record(r)
|
|
12
|
+
Attributes.new(
|
|
13
|
+
id: r['job_id']&.to_i,
|
|
14
|
+
subsystem: r['subsystem'],
|
|
15
|
+
job_name: r['job_name'],
|
|
16
|
+
jobnet_id: r['jobnet_id']&.to_i,
|
|
17
|
+
executor_id: r['executor_id']
|
|
18
|
+
)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def initialize(datasource)
|
|
22
|
+
@datasource = datasource
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
private def connect(&block)
|
|
26
|
+
@datasource.open_shared_connection(&block)
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def find_or_create(jobnet_id, job_ref)
|
|
30
|
+
connect {|conn|
|
|
31
|
+
job = find(conn, jobnet_id, job_ref) # optimize the most frequent case
|
|
32
|
+
if job
|
|
33
|
+
job
|
|
34
|
+
else
|
|
35
|
+
begin
|
|
36
|
+
create(conn, jobnet_id, job_ref)
|
|
37
|
+
rescue UniqueViolationException
|
|
38
|
+
find(conn, jobnet_id, job_ref) or raise "[BUG] Could not find/create job record: jobnet_id=#{jobnet_id}, ref=#{job_ref}"
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
}
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
private def find(conn, jobnet_id, job_ref)
|
|
45
|
+
record = conn.query_row(<<~EndSQL)
|
|
46
|
+
select
|
|
47
|
+
"job_id"
|
|
48
|
+
, "subsystem"
|
|
49
|
+
, "job_name"
|
|
50
|
+
, "executor_id"
|
|
51
|
+
, jobnet_id
|
|
52
|
+
from
|
|
53
|
+
jobs
|
|
54
|
+
where
|
|
55
|
+
jobnet_id = #{jobnet_id}
|
|
56
|
+
and "subsystem" = #{s job_ref.subsystem}
|
|
57
|
+
and "job_name" = #{s job_ref.name}
|
|
58
|
+
;
|
|
59
|
+
EndSQL
|
|
60
|
+
|
|
61
|
+
if record
|
|
62
|
+
Job.for_record(record)
|
|
63
|
+
else
|
|
64
|
+
nil
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
private def create(conn, jobnet_id, job_ref)
|
|
69
|
+
record = conn.query_row(<<~EndSQL)
|
|
70
|
+
insert into jobs
|
|
71
|
+
( "subsystem"
|
|
72
|
+
, "job_name"
|
|
73
|
+
, jobnet_id
|
|
74
|
+
)
|
|
75
|
+
values
|
|
76
|
+
( #{s job_ref.subsystem}
|
|
77
|
+
, #{s job_ref.name}
|
|
78
|
+
, #{jobnet_id}
|
|
79
|
+
)
|
|
80
|
+
returning "job_id", "subsystem", "job_name", jobnet_id
|
|
81
|
+
;
|
|
82
|
+
EndSQL
|
|
83
|
+
|
|
84
|
+
Job.for_record(record)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def locked?(job_ids)
|
|
88
|
+
count = connect {|conn|
|
|
89
|
+
conn.query_value(<<~EndSQL)
|
|
90
|
+
select
|
|
91
|
+
count(job_id)
|
|
92
|
+
from
|
|
93
|
+
jobs
|
|
94
|
+
where
|
|
95
|
+
job_id in (#{job_ids.join(',')})
|
|
96
|
+
and executor_id is not null
|
|
97
|
+
;
|
|
98
|
+
EndSQL
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
count.to_i > 0
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def locked_jobs(jobnet_id)
|
|
105
|
+
records = connect {|conn|
|
|
106
|
+
conn.query_rows(<<~EndSQL)
|
|
107
|
+
select
|
|
108
|
+
"job_id"
|
|
109
|
+
, "subsystem"
|
|
110
|
+
, "job_name"
|
|
111
|
+
, jobnet_id
|
|
112
|
+
, "executor_id"
|
|
113
|
+
from
|
|
114
|
+
jobs
|
|
115
|
+
where
|
|
116
|
+
jobnet_id = #{jobnet_id}
|
|
117
|
+
and executor_id is not null
|
|
118
|
+
;
|
|
119
|
+
EndSQL
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
if records.empty?
|
|
123
|
+
[]
|
|
124
|
+
else
|
|
125
|
+
record.map {|r| Job.for_record(r) }
|
|
126
|
+
end
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def lock(job_id, executor_id)
|
|
130
|
+
records = connect {|conn|
|
|
131
|
+
conn.execute_update(<<~EndSQL)
|
|
132
|
+
update jobs
|
|
133
|
+
set
|
|
134
|
+
executor_id = #{s executor_id}
|
|
135
|
+
where
|
|
136
|
+
job_id = #{job_id}
|
|
137
|
+
and executor_id is null
|
|
138
|
+
returning job_id
|
|
139
|
+
;
|
|
140
|
+
EndSQL
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
if records.empty?
|
|
144
|
+
raise DoubleLockError, "Could not lock job: job_id=#{job_id}"
|
|
145
|
+
end
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
# Unlock the job.
|
|
149
|
+
# Returns true if successfully unlocked, otherwise false.
|
|
150
|
+
# FIXME: raise an exception on failing unlock?
|
|
151
|
+
def unlock(job_id, executor_id)
|
|
152
|
+
records = connect {|conn|
|
|
153
|
+
conn.execute_update(<<~EndSQL)
|
|
154
|
+
update jobs
|
|
155
|
+
set
|
|
156
|
+
executor_id = null
|
|
157
|
+
where
|
|
158
|
+
job_id = #{job_id}
|
|
159
|
+
and executor_id = #{s executor_id}
|
|
160
|
+
returning job_id
|
|
161
|
+
;
|
|
162
|
+
EndSQL
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
not records.empty?
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def clear_lock_all(jobnet_id)
|
|
169
|
+
connect {|conn|
|
|
170
|
+
conn.execute_update(<<~EndSQL)
|
|
171
|
+
update jobs
|
|
172
|
+
set
|
|
173
|
+
executor_id = null
|
|
174
|
+
where
|
|
175
|
+
jobnet_id = #{jobnet_id}
|
|
176
|
+
;
|
|
177
|
+
EndSQL
|
|
178
|
+
}
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
end # class Job
|
|
182
|
+
|
|
183
|
+
end
|
|
184
|
+
end
|