capistrano_multiconfig_parallel 2.0.0.rc1 → 2.0.0.rc2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3f293dd460a9b6468a63c41cabe277f8a948b419
4
- data.tar.gz: 07307d95d8574a28775a03549afa110d233d730e
3
+ metadata.gz: c7cc02538db7ad911dd5b61aa6eab9f9d651ac64
4
+ data.tar.gz: e81e18d1337ccfeae94260e8ed40e2319377f7aa
5
5
  SHA512:
6
- metadata.gz: 6209f4db889a5a4c29cf83476509405e56f796180f2024f5945057ce633eedbfde0dbcc4048684947aef4c981071cb1fa99caab3bd142672e7a8dc0c0c98f507
7
- data.tar.gz: a5231899ad5ded76359d19f625e921114aa4f3dd4aa1dc8046ec1179f398f2eaf94b4cddbcac7ca65bd66c33fc7aa5d86b03a762aa0f629811f6b3ae7f56023c
6
+ metadata.gz: 4f69ea91b5e891f4bd5186506734582c6d70785650f7ea9c08c9cc091bbe1bc084739084fe5c8a3277d99038f74d206087335714bacdebf2da11c41c8baa74ee
7
+ data.tar.gz: 4848c50cabcf6a0daa0f72bb9358f81aa49769746c9748e761954510b42c4682f4dbce620943adcdc06047679c39028dfb9fb82c3409376279007add787a6425
@@ -6,7 +6,7 @@ module CapistranoMulticonfigParallel
6
6
  # manager class that handles workers
7
7
  class CelluloidManager
8
8
  include CapistranoMulticonfigParallel::BaseActorHelper
9
- attr_accessor :jobs, :job_to_worker, :worker_to_job, :job_to_condition, :mutex, :registration_complete, :workers_terminated, :stderr_buffer
9
+ attr_accessor :jobs, :job_to_worker, :worker_to_job, :job_to_condition, :mutex, :registration_complete, :workers_terminated, :stderr_buffer
10
10
 
11
11
  attr_reader :worker_supervisor, :workers
12
12
  trap_exit :worker_died
@@ -40,11 +40,11 @@ module CapistranoMulticonfigParallel
40
40
 
41
41
  # call to send an actor
42
42
  # a job
43
- def delegate_job(job)
43
+ def delegate_job(job, old_job = "")
44
44
  @jobs[job.id] = job
45
45
  # debug(@jobs)
46
46
  # start work and send it to the background
47
- @workers.work(job, Actor.current)
47
+ @workers.work(job, Actor.current, old_job)
48
48
  end
49
49
 
50
50
  # call back from actor once it has received it's job
@@ -72,6 +72,7 @@ module CapistranoMulticonfigParallel
72
72
  wait_task_confirmations
73
73
  end
74
74
  terminal_show
75
+ async.check_workers_done?
75
76
  condition = @workers_terminated.wait
76
77
  until condition.present?
77
78
  sleep(0.1) # keep current thread alive
@@ -80,6 +81,17 @@ module CapistranoMulticonfigParallel
80
81
  terminal_show
81
82
  end
82
83
 
84
+ def check_workers_done?
85
+ Thread.new do
86
+ loop do
87
+ if Actor.current.alive? && all_workers_finished?
88
+ @workers_terminated.signal('completed')
89
+ break
90
+ end
91
+ end
92
+ end
93
+ end
94
+
83
95
  def terminal_show
84
96
  Celluloid::Actor[:terminal_server].async.notify_time_change(CapistranoMulticonfigParallel::TerminalTable.topic, type: 'output') if Celluloid::Actor[:terminal_server].alive?
85
97
  end
@@ -169,10 +181,10 @@ module CapistranoMulticonfigParallel
169
181
  worker = get_worker_for_job(job_id)
170
182
  if worker.alive?
171
183
  worker.publish_rake_event('approved' => 'yes',
172
- 'action' => 'invoke',
173
- 'job_id' => job.id,
174
- 'task' => task
175
- )
184
+ 'action' => 'invoke',
185
+ 'job_id' => job.id,
186
+ 'task' => task
187
+ )
176
188
  end
177
189
  end
178
190
  end
@@ -191,7 +203,7 @@ module CapistranoMulticonfigParallel
191
203
 
192
204
  def can_tag_staging?
193
205
  @job_manager.can_tag_staging? && @job_manager.tag_staging_exists? &&
194
- @jobs.find { |_job_id, job| job.stage == 'production' }.blank?
206
+ @jobs.find { |_job_id, job| job.stage == 'production' }.blank?
195
207
  end
196
208
 
197
209
  def dispatch_new_job(job, options = {})
@@ -201,7 +213,7 @@ module CapistranoMulticonfigParallel
201
213
  new_job_options = job.options.except!('id', 'status', 'exit_status').merge('env_options' => job.env_options.merge(env_opts))
202
214
  new_job = CapistranoMulticonfigParallel::Job.new(@job_manager, new_job_options.merge(options))
203
215
  log_to_file("Trying to DiSPATCH new JOB #{new_job.inspect}")
204
- async.delegate_job(new_job) unless job.rolling_back?
216
+ async.delegate_job(new_job, job) unless job.rolling_back?
205
217
  end
206
218
 
207
219
  # lookup status of job by asking actor running it
@@ -227,6 +239,7 @@ module CapistranoMulticonfigParallel
227
239
  job.rollback_changes_to_application
228
240
  @worker_to_job.delete(mailbox.address)
229
241
  log_to_file("RESTARTING: worker job #{job.inspect} with mailbox #{mailbox.inspect} and #{mailbox.address.inspect} died for reason: #{reason}")
242
+
230
243
  dispatch_new_job(job, skip_env_options: true, action: 'deploy:rollback')
231
244
  end
232
245
  end
@@ -26,7 +26,7 @@ module CapistranoMulticonfigParallel
26
26
  :job, :manager, :job_id, :app_name, :env_name, :action_name, :env_options, :machine, :socket_connection, :task_argv,
27
27
  :rake_tasks, :current_task_number, # tracking tasks
28
28
  :successfull_subscription, :subscription_channel, :publisher_channel, # for subscriptions and publishing events
29
- :job_termination_condition, :invocation_chain, :filename, :worker_log, :exit_status
29
+ :job_termination_condition, :invocation_chain, :filename, :worker_log, :exit_status, :old_job
30
30
  ]
31
31
 
32
32
  attr_reader *CapistranoMulticonfigParallel::CelluloidWorker::ATTRIBUTE_LIST
@@ -35,13 +35,14 @@ module CapistranoMulticonfigParallel
35
35
  def initialize(*args)
36
36
  end
37
37
 
38
- def work(job, manager)
38
+ def work(job, manager, old_job)
39
39
  @job = job
40
+ @old_job = old_job
40
41
  @job_id = job.id
41
42
  @worker_state = job.status
42
43
  @manager = manager
43
44
  @job_confirmation_conditions = []
44
- log_to_file("worker #{@job_id} received #{job.inspect}")
45
+ log_to_file("worker #{@job_id} received #{job.inspect} and #{old_job.inspect}")
45
46
  @subscription_channel = "#{CapistranoSentinel::RequestHooks::PUBLISHER_PREFIX}#{@job_id}"
46
47
  @machine = CapistranoMulticonfigParallel::StateMachine.new(@job, Actor.current)
47
48
  @manager.setup_worker_conditions(@job)
@@ -60,6 +61,9 @@ module CapistranoMulticonfigParallel
60
61
 
61
62
  def start_task
62
63
  log_to_file("exec worker #{@job_id} starts task and subscribes to #{@subscription_channel}")
64
+ if @old_job.present? && @old_job.is_a?(CapistranoMulticonfigParallel::Job)
65
+ @old_job.new_jobs_dispatched << @job.id
66
+ end
63
67
  @socket_connection = CelluloidPubsub::Client.new(actor: Actor.current, enable_debug: debug_websocket?, channel: subscription_channel, log_file_path: websocket_config.fetch('log_file_path', nil))
64
68
  end
65
69
 
@@ -111,6 +115,7 @@ module CapistranoMulticonfigParallel
111
115
 
112
116
  def check_gitflow
113
117
  return if @job.stage != 'staging' || !@manager.can_tag_staging? || !executed_task?(CapistranoMulticonfigParallel::GITFLOW_TAG_STAGING_TASK)
118
+ mark_for_dispatching_new_job
114
119
  @manager.dispatch_new_job(@job, stage: 'production')
115
120
  end
116
121
 
@@ -165,7 +170,6 @@ module CapistranoMulticonfigParallel
165
170
  log_to_file("worker #{@job_id} triest to transition from #{@machine.state} to #{name}") unless options[:bundler]
166
171
  @machine.go_to_transition(name.to_s, options)
167
172
  error_message = "worker #{@job_id} task #{name} failed "
168
- # @manager.worker_died(Actor.current, error_message) if job.failed?
169
173
  raise(CapistranoMulticonfigParallel::CelluloidWorker::TaskFailed.new(error_message), error_message) if job.failed? # force worker to rollback
170
174
  end
171
175
 
@@ -178,17 +182,22 @@ module CapistranoMulticonfigParallel
178
182
  def finish_worker(exit_status)
179
183
  log_to_file("worker #{job_id} tries to terminate with exit_status #{exit_status}")
180
184
  @manager.mark_completed_remaining_tasks(@job) if Actor.current.alive?
181
- exit_status == 0 ? update_machine_state('FINISHED') : update_machine_state('DEAD')
182
- # @manager.worker_died(Actor.current, exit_status) if exit_status != 0
183
- @manager.workers_terminated.signal('completed') if @manager.present? && @manager.alive? && @manager.all_workers_finished?
185
+ update_machine_state('FINISHED') if exit_status == 0
186
+ @manager.workers_terminated.signal('completed') if !@job.marked_for_dispatching_new_job? && @manager.present? && @manager.alive? && @manager.all_workers_finished?
187
+ end
188
+
189
+ def mark_for_dispatching_new_job
190
+ @job.will_dispatch_new_job = @job.new_jobs_dispatched.size + 1 unless @job.rolling_back?
184
191
  end
185
192
 
186
193
  def notify_finished(exit_status)
194
+ mark_for_dispatching_new_job if exit_status != 0
195
+ @job.exit_status = exit_status
187
196
  finish_worker(exit_status)
188
- return if exit_status == 0
189
- error_message = "worker #{@job_id} task failed with exit status #{exit_status.inspect} "
190
- raise(CapistranoMulticonfigParallel::CelluloidWorker::TaskFailed.new(error_message), error_message)
191
- end
197
+ return if exit_status == 0
198
+ error_message = "worker #{@job_id} task failed with exit status #{exit_status.inspect} "
199
+ raise(CapistranoMulticonfigParallel::CelluloidWorker::TaskFailed.new(error_message), error_message)
200
+ end
192
201
 
193
202
  # def inspect
194
203
  # to_s
@@ -57,15 +57,15 @@ module CapistranoMulticonfigParallel
57
57
  end
58
58
 
59
59
  def check_exit_status
60
- return if @runner_status.exit_status.blank?
60
+ exit_status = @runner_status.exit_status
61
+ return if exit_status.blank?
61
62
  @timer.cancel
62
- @job.exit_status = @runner_status.exit_status
63
- log_to_file("worker #{@job_id} startsnotify finished with exit status #{@job.exit_status.inspect}")
63
+ log_to_file("worker #{@job_id} startsnotify finished with exit status #{exit_status.inspect}")
64
64
  if @actor.present? && @actor.respond_to?(:notify_finished)
65
65
  if @actor.respond_to?(:async) && @synchronicity == :async
66
- @actor.async.notify_finished(@job.exit_status)
66
+ @actor.async.notify_finished(exit_status)
67
67
  elsif @synchronicity == :sync
68
- @actor.notify_finished(@job.exit_status)
68
+ @actor.notify_finished(exit_status)
69
69
  end
70
70
  end
71
71
  end
@@ -62,7 +62,6 @@ module CapistranoMulticonfigParallel
62
62
 
63
63
  def watch_handler(process)
64
64
  @process ||= process
65
- process_runner.check_exit_status
66
65
  end
67
66
 
68
67
  def io_callback(io, data)
@@ -6,7 +6,7 @@ module CapistranoMulticonfigParallel
6
6
  include CapistranoMulticonfigParallel::ApplicationHelper
7
7
 
8
8
  attr_reader :options, :application, :manager, :bundler_status
9
- attr_writer :status, :exit_status, :bundler_status
9
+ attr_writer :status, :exit_status, :bundler_status, :new_jobs_dispatched, :will_dispatch_new_job
10
10
 
11
11
  delegate :stderr_buffer,
12
12
  to: :manager
@@ -80,7 +80,7 @@ module CapistranoMulticonfigParallel
80
80
  def worker_state
81
81
  worker_obj = worker
82
82
  default = status.to_s.upcase.red
83
- worker_obj.present? && worker_obj.alive? ? worker_obj.worker_state : default
83
+ worker_died? ? default : worker_obj.worker_state
84
84
  end
85
85
 
86
86
  def id
@@ -95,7 +95,10 @@ module CapistranoMulticonfigParallel
95
95
  { name: 'env_options', default: {} },
96
96
  { name: 'path', default: nil },
97
97
  { name: 'status', default: :unstarted },
98
- { name: 'exit_status', default: nil }
98
+ { name: 'exit_status', default: nil },
99
+ { name: 'bundler_status', default: nil },
100
+ { name: 'new_jobs_dispatched', default: [] },
101
+ { name: 'will_dispatch_new_job', default: nil },
99
102
  ].each do |hash|
100
103
  define_method hash[:name] do
101
104
  value = @options.fetch(hash[:name], hash[:default])
@@ -123,8 +126,19 @@ module CapistranoMulticonfigParallel
123
126
  ['deploy:rollback'].include?(action)
124
127
  end
125
128
 
129
+ def marked_for_dispatching_new_job?
130
+ will_dispatch_new_job.to_i != new_jobs_dispatched.size
131
+ end
132
+
133
+ def new_jobs_dispatched_finished?
134
+ if marked_for_dispatching_new_job?
135
+ sleep(0.1) until will_dispatch_new_job.to_i == new_jobs_dispatched.size
136
+ end
137
+ true
138
+ end
139
+
126
140
  def crashed?
127
- worker_died? || failed? || dead? || exit_status.present?
141
+ worker_died? || failed? || exit_status.present?
128
142
  end
129
143
 
130
144
  def dead?
@@ -132,11 +146,11 @@ module CapistranoMulticonfigParallel
132
146
  end
133
147
 
134
148
  def worker_died?
135
- worker.blank? || !worker.alive?
149
+ dead? || worker == nil || worker.dead?
136
150
  end
137
151
 
138
152
  def work_done?
139
- finished? || crashed?
153
+ new_jobs_dispatched_finished? && (finished? || crashed?)
140
154
  end
141
155
 
142
156
  def inspect
@@ -149,8 +163,8 @@ module CapistranoMulticonfigParallel
149
163
 
150
164
  def to_json
151
165
  hash = {}
152
- %w(id app stage action task_arguments env_options status exit_status).each do |key|
153
- hash[key] = send(key)
166
+ %w(id app stage action task_arguments env_options status exit_status bundler_status will_dispatch_new_job new_jobs_dispatched).each do |key|
167
+ hash[key] = send(key).inspect
154
168
  end
155
169
  hash
156
170
  end
@@ -211,11 +211,14 @@ module CapistranoMulticonfigParallel
211
211
 
212
212
  if rvm_enabled_for_job?
213
213
  create_job_tempfile_command(command_text)
214
+ log_to_file "JOB #{@job_id} created Tempfile #{@tempfile.path} with contents #{File.read(@tempfile.path)}"
214
215
  "ruby #{@tempfile.path}"
215
216
  else
216
- <<-CMD
217
+ final_command=<<-CMD
217
218
  cd #{job_path} && bundle exec ruby -e "#{command_text}"
218
219
  CMD
220
+ log_to_file "JOB #{@job_id} prepared command #{final_command}"
221
+ final_command
219
222
  end
220
223
  end
221
224
 
@@ -224,7 +227,7 @@ module CapistranoMulticonfigParallel
224
227
  prepare_application_for_deployment
225
228
  # config_flags = CapistranoMulticonfigParallel.configuration_flags.merge("capistrano_version": job_capistrano_version)
226
229
  environment_options = setup_command_line.join(' ')
227
- command = "#{fetch_bundler_check_command(@job_final_gemfile)} && WEBSOCKET_LOGGING=#{debug_websocket?} LOG_FILE=#{websocket_config.fetch('log_file_path', nil)} #{bundle_gemfile_env(@job_final_gemfile)} bundle exec cap #{job_stage} #{capistrano_action} #{environment_options}"
230
+ command = "#{fetch_bundler_check_command(@job_final_gemfile)} && WEBSOCKET_LOGGING=#{true} LOG_FILE=#{websocket_config.fetch('log_file_path', nil)} #{bundle_gemfile_env(@job_final_gemfile)} bundle exec cap #{job_stage} #{capistrano_action} #{environment_options}"
228
231
 
229
232
  get_command_script(command)
230
233
  end
@@ -239,7 +242,7 @@ module CapistranoMulticonfigParallel
239
242
  end
240
243
 
241
244
  def prepare_application_for_deployment
242
- if ENV['MULTI_CAP_WEB_APP']
245
+ if ENV['MULTI_CAP_WEB_APP'].present?
243
246
  bundler_worker = CapistranoMulticonfigParallel::BundlerWorker.new
244
247
  result = bundler_worker.work(job)
245
248
  end
@@ -10,7 +10,7 @@ module CapistranoMulticonfigParallel
10
10
  MAJOR = 2
11
11
  MINOR = 0
12
12
  TINY = 0
13
- PRE = 'rc1'
13
+ PRE = 'rc2'
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join('.')
16
16
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: capistrano_multiconfig_parallel
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0.rc1
4
+ version: 2.0.0.rc2
5
5
  platform: ruby
6
6
  authors:
7
7
  - bogdanRada