deploy_pin 1.3.0 → 1.3.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a760ef5554d4821d4e57eca80bd547a24f5456c7e2bd27768fc2d62db3bad25e
4
- data.tar.gz: 33e218e88444b4362b29d7f506fcdc455f07c07b4c6760228043b5f403687948
3
+ metadata.gz: f3006ccc3913b4cc7ee0b5d68b316ffb70ecef2bbfeae27c7efec65422246cdb
4
+ data.tar.gz: d055a8554b590bc039915d3a2866f23aa8541db9ffe8c2c933294f54c2013785
5
5
  SHA512:
6
- metadata.gz: fbae2f1401711aabf1e88e3e01daeb2b8a1e07a4f3072fb8d54eb9f0f40f0bb74a4eaaed7859cd4119574544a2814393a44dcb7297808db6f89dd7e659d03220
7
- data.tar.gz: cb8203f11fefb55c2e525fb2b6a2ca82e0d8791b69c64717d3f830bf2c5a3cf91977cb3e3842d780aa6084171795154eb548546a610798a60c53938b35f7173b
6
+ metadata.gz: 70d4054142995c62609666711a87d4d4e42783bf4631e61f3a43e3407a9cd68654de65b0925655ca416fb65e41bccd3a2246125e446f5f4d8a9cb48f70e7ffd4
7
+ data.tar.gz: 654cbb997e23bf9a2cc9d8579e71646f68fd669dfd92235da2a1d15b8b3d9775b01db714ce99e79e23e6389282a907c2f9ae5b573c348bd4b0d3f43105989903
@@ -19,7 +19,11 @@ module DeployPin
19
19
  yield(index, _tasks.count, task, executable)
20
20
 
21
21
  # run if executable
22
- task.run if executable
22
+ if executable
23
+ run_with_timeout(!task.explicit_timeout? && !task.parallel?) do
24
+ task.run
25
+ end
26
+ end
23
27
 
24
28
  # mark each task as done
25
29
  task.mark unless task.done?
@@ -46,23 +50,30 @@ module DeployPin
46
50
  end
47
51
 
48
52
  private
53
+ # :reek:UtilityFunction
54
+ def files
55
+ Dir["#{DeployPin.tasks_path}/*.rb"]
56
+ end
49
57
 
50
- def files
51
- Dir["#{DeployPin.tasks_path}/*.rb"]
52
- end
58
+ def tasks
59
+ files.map do |file|
60
+ task = DeployPin::Task.new(file)
61
+ task.parse_file
53
62
 
54
- def tasks
55
- files.map do |file|
56
- task = DeployPin::Task.new(file)
57
- task.parse_file
63
+ # check if task is suitable
64
+ task if task_criteria.suitable?(task)
65
+ end.compact.sort # sort by group position in config
66
+ end
58
67
 
59
- # check if task is suitable
60
- task if task_criteria.suitable?(task)
61
- end.compact.sort # sort by group position in config
62
- end
68
+ def task_criteria
69
+ @task_criteria ||= DeployPin::TaskCriteria.new(identifiers: identifiers)
70
+ end
63
71
 
64
- def task_criteria
65
- @task_criteria ||= DeployPin::TaskCriteria.new(identifiers: identifiers)
66
- end
72
+ # :reek:UtilityFunction and :reek:ControlParameter
73
+ def run_with_timeout(under_timeout, &block)
74
+ return yield unless under_timeout
75
+
76
+ DeployPin::Database.execute_with_timeout(DeployPin.statement_timeout, **{}, &block)
77
+ end
67
78
  end
68
79
  end
@@ -2,6 +2,9 @@
2
2
 
3
3
  module DeployPin
4
4
  module Database
5
+ PG_TIMEOUT_STATEMENT = 'SET statement_timeout TO %s'
6
+ MYSQL_TIMEOUT_STATEMENT = 'SET max_execution_time = %s'
7
+
5
8
  extend self
6
9
 
7
10
  # Run a block under a sql maximum timeout.
@@ -46,7 +49,7 @@ module DeployPin
46
49
 
47
50
  return call_block_under_timeout(timeout, &blk) unless params.key? :connected_to
48
51
 
49
- klass = params[:connected_to].key? :database ? ActiveRecord::Base : ::ApplicationRecord
52
+ klass = params[:connected_to].key?(:database) ? ActiveRecord::Base : ::ApplicationRecord
50
53
  klass.connected_to(**params[:connected_to]) do
51
54
  call_block_under_timeout(timeout, &blk)
52
55
  end
@@ -65,32 +68,24 @@ module DeployPin
65
68
 
66
69
  timeout_statement =
67
70
  if postgresql?
68
- postgresql_timeout_statement
71
+ PG_TIMEOUT_STATEMENT
69
72
  elsif mysql?
70
- mysql_timeout_statement
73
+ MYSQL_TIMEOUT_STATEMENT
71
74
  end
72
75
 
73
- connection.select_all "#{timeout_statement} #{connection.quote(timeout_in_milliseconds)}"
76
+ connection.execute timeout_statement % connection.quote(timeout_in_milliseconds)
74
77
  end
75
78
 
76
79
  def postgresql?
77
80
  connection.adapter_name =~ /postg/i
78
81
  end
79
82
 
80
- def postgresql_timeout_statement
81
- "SET statement_timeout TO"
82
- end
83
-
84
83
  def mysql?
85
84
  connection.adapter_name =~ /mysql/i
86
85
  end
87
86
 
88
- def mysql_timeout_statement
89
- "SET max_execution_time ="
90
- end
91
-
92
87
  def connection
93
88
  ActiveRecord::Base.connection
94
89
  end
95
90
  end
96
- end
91
+ end
@@ -0,0 +1,95 @@
1
+ # frozen_string_literal: true
2
+
3
+ module DeployPin
4
+ # Parallel wrapper to run parallel tasks using database statement timeout.
5
+ # This wrapper keeps parallel interface, but running the processes under db statement timeout.
6
+ #
7
+ # In order to use this wrapper, just use call parallel methods with `parallel_`. Ex.:
8
+ # parallel_each(1..2, in_processes: 2, timeout: 0.3.seconds) do |i|
9
+ # puts "Item: #{i}, Worker: #{Parallel.worker_number}"
10
+ # ActiveRecord::Base.connection.execute("<some db query>")
11
+ # end
12
+ #
13
+ # In order to pass more `timeout` options, it requires to pass an array, like:
14
+ # parallel_each(1..2, in_processes: 2, timeout: [0.3.seconds, { connected_to: { role: :reading } }]) do |i|
15
+ # puts "Item: #{i}, Worker: #{Parallel.worker_number}"
16
+ # ActiveRecord::Base.connection.execute("<some db query>")
17
+ # end
18
+ module ParallelWrapper
19
+ PARALLEL_PREFIX = 'parallel_'
20
+
21
+ # :reek:TooManyInstanceVariables
22
+ class ParallelRunner
23
+ def initialize(method_name, *args, &db_block)
24
+ @method_name = method_name
25
+ @db_block = db_block
26
+
27
+ if args.last.is_a?(Hash) && args.last.key?(:timeout)
28
+ @timeout_args = args.pop
29
+ prepare_timeout_args
30
+ end
31
+
32
+ @parallel_args = args
33
+ end
34
+
35
+ def run
36
+ raise 'You must provide at least one argument for parallel methods' if parallel_args.empty?
37
+
38
+ Parallel.send(parallel_method_name, *parallel_args) do |*block_args|
39
+ ActiveRecord::Base.connection_pool.with_connection do
40
+ DeployPin::Database.execute_with_timeout(timeout, **timeout_params) do
41
+ db_block.call(*block_args)
42
+ end
43
+ end
44
+ end
45
+ end
46
+
47
+ private
48
+
49
+ attr_accessor :method_name, :parallel_args, :db_block
50
+
51
+ def prepare_timeout_args
52
+ timeout = @timeout_args[:timeout]
53
+ if timeout.is_a?(Array)
54
+ @timeout = timeout.shift
55
+ @timeout_params = timeout.first
56
+ else
57
+ @timeout = timeout
58
+ end
59
+ end
60
+
61
+ def timeout
62
+ @timeout ||= DeployPin.statement_timeout
63
+ end
64
+
65
+ def timeout_params
66
+ @timeout_params ||= {}
67
+ end
68
+
69
+ def parallel_method_name
70
+ @parallel_method_name ||= method_name.to_s.gsub(PARALLEL_PREFIX, '').to_sym
71
+ end
72
+ end
73
+
74
+ def method_missing(name, *args, &block)
75
+ return super unless respond_to_missing?(name)
76
+
77
+ ParallelRunner.new(name, *args, &block).run
78
+ end
79
+
80
+ # :reek:ManualDispatch and :reek:BooleanParameter
81
+ def respond_to_missing?(method_name, include_private = false)
82
+ return super unless parallel_prefix_pattern.match? method_name
83
+
84
+ parallel_method_name = method_name.to_s.gsub(PARALLEL_PREFIX, '').to_sym
85
+
86
+ Parallel.respond_to?(parallel_method_name) || super
87
+ end
88
+
89
+ private
90
+
91
+ def parallel_prefix_pattern
92
+ @parallel_prefix_pattern ||= /\A#{PARALLEL_PREFIX}/
93
+ end
94
+ end
95
+ end
@@ -3,11 +3,15 @@
3
3
  # Task wrapper
4
4
  module DeployPin
5
5
  class Task
6
+ extend ::DeployPin::ParallelWrapper
7
+ include ::DeployPin::ParallelWrapper
8
+
6
9
  attr_reader :file,
7
10
  :uuid,
8
11
  :group,
9
12
  :title,
10
- :script
13
+ :script,
14
+ :explicit_timeout
11
15
 
12
16
  def initialize(file)
13
17
  @file = file
@@ -15,6 +19,8 @@ module DeployPin
15
19
  @group = nil
16
20
  @title = ''
17
21
  @script = ''
22
+ @explicit_timeout = false
23
+ @parallel = false
18
24
  end
19
25
 
20
26
  def run
@@ -31,6 +37,14 @@ module DeployPin
31
37
  DeployPin::Record.where(uuid: uuid).exists?
32
38
  end
33
39
 
40
+ def explicit_timeout?
41
+ @explicit_timeout
42
+ end
43
+
44
+ def parallel?
45
+ @parallel
46
+ end
47
+
34
48
  def parse_file
35
49
  File.foreach(file) do |line|
36
50
  case line.strip
@@ -41,6 +55,9 @@ module DeployPin
41
55
  @title = Regexp.last_match(1).strip
42
56
  when /\A[^#].*/
43
57
  @script += line
58
+
59
+ @explicit_timeout = true if line =~ /Database.execute_with_timeout.*/
60
+ @parallel = true if line =~ /[Pp]arallel.*/
44
61
  end
45
62
  end
46
63
  end
@@ -60,13 +77,13 @@ module DeployPin
60
77
 
61
78
  protected
62
79
 
63
- # for sorting
64
- def <=>(other)
65
- group_index <=> other.group_index
66
- end
80
+ # for sorting
81
+ def <=>(other)
82
+ group_index <=> other.group_index
83
+ end
67
84
 
68
- def group_index
69
- DeployPin.groups.index(group)
70
- end
85
+ def group_index
86
+ DeployPin.groups.index(group)
87
+ end
71
88
  end
72
89
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module DeployPin
4
- VERSION = '1.3.0'
4
+ VERSION = '1.3.1'
5
5
  end
data/lib/deploy_pin.rb CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  require 'deploy_pin/runner'
4
4
  require 'deploy_pin/collector'
5
+ require 'deploy_pin/parallel_wrapper'
5
6
  require 'deploy_pin/task'
6
7
  require 'deploy_pin/task_criteria'
7
8
  require 'deploy_pin/engine'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: deploy_pin
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Viktor Sych
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-16 00:00:00.000000000 Z
11
+ date: 2022-08-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: colorize
@@ -166,6 +166,7 @@ files:
166
166
  - lib/deploy_pin/collector.rb
167
167
  - lib/deploy_pin/database.rb
168
168
  - lib/deploy_pin/engine.rb
169
+ - lib/deploy_pin/parallel_wrapper.rb
169
170
  - lib/deploy_pin/runner.rb
170
171
  - lib/deploy_pin/task.rb
171
172
  - lib/deploy_pin/task_criteria.rb