sidekiq-web_custom 0.2.0
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 +7 -0
- data/.circleci/config.yml +109 -0
- data/.gitignore +18 -0
- data/.rspec +3 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Dockerfile +18 -0
- data/Gemfile +14 -0
- data/Gemfile.lock +182 -0
- data/LICENSE.txt +21 -0
- data/Makefile +40 -0
- data/README.md +92 -0
- data/Rakefile +8 -0
- data/bin/all_workers +69 -0
- data/bin/bundle +114 -0
- data/bin/publish +40 -0
- data/bin/publish_git +38 -0
- data/bin/publish_ruby_gems +22 -0
- data/bin/rails +18 -0
- data/bin/sidekiq +29 -0
- data/bin/sidekiqmon +29 -0
- data/docker-compose.yml +43 -0
- data/dummy_rails/.rspec +4 -0
- data/dummy_rails/app/assets/config/manifest.js +0 -0
- data/dummy_rails/app/controllers/application_controller.rb +2 -0
- data/dummy_rails/app/helpers/application_helper.rb +2 -0
- data/dummy_rails/app/views/layouts/application.html.erb +15 -0
- data/dummy_rails/app/views/layouts/mailer.html.erb +13 -0
- data/dummy_rails/app/workers/exclude_hard_worker.rb +15 -0
- data/dummy_rails/app/workers/exclude_lazy_worker.rb +11 -0
- data/dummy_rails/app/workers/exclude_random_raise_worker.rb +11 -0
- data/dummy_rails/app/workers/hard_worker.rb +15 -0
- data/dummy_rails/app/workers/lazy_worker.rb +10 -0
- data/dummy_rails/app/workers/random_raise_worker.rb +12 -0
- data/dummy_rails/app/workers/taco_worker.rb +12 -0
- data/dummy_rails/app/workers/tostada_worker.rb +11 -0
- data/dummy_rails/bin/rspec +5 -0
- data/dummy_rails/config.ru +5 -0
- data/dummy_rails/config/application.rb +20 -0
- data/dummy_rails/config/boot.rb +5 -0
- data/dummy_rails/config/environment.rb +5 -0
- data/dummy_rails/config/environments/development.rb +52 -0
- data/dummy_rails/config/environments/production.rb +88 -0
- data/dummy_rails/config/environments/test.rb +40 -0
- data/dummy_rails/config/initializers/assets.rb +14 -0
- data/dummy_rails/config/initializers/cookies_serializer.rb +5 -0
- data/dummy_rails/config/initializers/filter_parameter_logging.rb +4 -0
- data/dummy_rails/config/initializers/sidekiq-web_custom.rb +3 -0
- data/dummy_rails/config/initializers/wrap_parameters.rb +14 -0
- data/dummy_rails/config/locales/en.yml +33 -0
- data/dummy_rails/config/puma.rb +37 -0
- data/dummy_rails/config/routes.rb +5 -0
- data/dummy_rails/config/secrets.yml +5 -0
- data/dummy_rails/config/spring.rb +5 -0
- data/dummy_rails/config/storage.yml +34 -0
- data/dummy_rails/package.json +5 -0
- data/dummy_rails/spec/spec_helper.rb +50 -0
- data/lib/load_random_workers.rb +25 -0
- data/lib/sidekiq/views/actions/queues/delete.erb +12 -0
- data/lib/sidekiq/views/actions/queues/drain_queue.erb +4 -0
- data/lib/sidekiq/views/actions/queues/pause.erb +13 -0
- data/lib/sidekiq/views/actions/retries/delete.erb +5 -0
- data/lib/sidekiq/views/actions/retries/execute.erb +7 -0
- data/lib/sidekiq/views/actions/scheduled/delete.erb +5 -0
- data/lib/sidekiq/views/actions/scheduled/execute.erb +7 -0
- data/lib/sidekiq/views/queues.erb +64 -0
- data/lib/sidekiq/views/retries.erb +123 -0
- data/lib/sidekiq/views/scheduled.erb +97 -0
- data/lib/sidekiq/web_custom.rb +95 -0
- data/lib/sidekiq/web_custom/configuration.rb +112 -0
- data/lib/sidekiq/web_custom/job.rb +11 -0
- data/lib/sidekiq/web_custom/processor.rb +82 -0
- data/lib/sidekiq/web_custom/queue.rb +12 -0
- data/lib/sidekiq/web_custom/timeout.rb +64 -0
- data/lib/sidekiq/web_custom/version.rb +14 -0
- data/lib/sidekiq/web_custom/web_action.rb +38 -0
- data/lib/sidekiq/web_custom/web_app.rb +46 -0
- data/sidekiq-web_custom.gemspec +37 -0
- metadata +151 -0
@@ -0,0 +1,97 @@
|
|
1
|
+
<header class="row">
|
2
|
+
<div class="col-sm-5">
|
3
|
+
<h3><%= t('ScheduledJobs') %></h3>
|
4
|
+
</div>
|
5
|
+
<% if @scheduled.size > 0 && @total_size > @count %>
|
6
|
+
<div class="col-sm-4">
|
7
|
+
<%= erb :_paging, locals: { url: "#{root_path}scheduled" } %>
|
8
|
+
</div>
|
9
|
+
<% end %>
|
10
|
+
<%= filtering('scheduled') %>
|
11
|
+
</header>
|
12
|
+
|
13
|
+
<% if @scheduled.size > 0 %>
|
14
|
+
|
15
|
+
<form action="<%= root_path %>scheduled" method="post">
|
16
|
+
<%= csrf_tag %>
|
17
|
+
<div class="table_container">
|
18
|
+
<table class="table table-striped table-bordered">
|
19
|
+
<thead>
|
20
|
+
<tr>
|
21
|
+
<th class="checkbox-column">
|
22
|
+
<input type="checkbox" class="check_all" />
|
23
|
+
</th>
|
24
|
+
<th><%= t('When') %></th>
|
25
|
+
<th><%= t('Queue') %></th>
|
26
|
+
<th><%= t('Job') %></th>
|
27
|
+
<th><%= t('Arguments') %></th>
|
28
|
+
<th><%= t('Actions') %></th>
|
29
|
+
</tr>
|
30
|
+
</thead>
|
31
|
+
<% @scheduled.each do |entry| %>
|
32
|
+
<tr>
|
33
|
+
<td>
|
34
|
+
<input type='checkbox' name='key[]' value='<%= job_params(entry.item, entry.score) %>' />
|
35
|
+
</td>
|
36
|
+
<td>
|
37
|
+
<a href="<%= root_path %>scheduled/<%= job_params(entry.item, entry.score) %>"><%= relative_time(entry.at) %></a>
|
38
|
+
</td>
|
39
|
+
<td>
|
40
|
+
<a href="<%= root_path %>queues/<%= entry.queue %>"><%= entry.queue %></a>
|
41
|
+
</td>
|
42
|
+
<td>
|
43
|
+
<%= entry.display_class %>
|
44
|
+
<%= display_tags(entry, "scheduled") %>
|
45
|
+
</td>
|
46
|
+
<td>
|
47
|
+
<div class="args"><%= display_args(entry.display_args) %></div>
|
48
|
+
</td>
|
49
|
+
<td>
|
50
|
+
__sidekiq_web_custom_replacement__
|
51
|
+
</td>
|
52
|
+
</tr>
|
53
|
+
<% end %>
|
54
|
+
</table>
|
55
|
+
</div>
|
56
|
+
<input class="btn btn-danger pull-right flip" type="submit" name="delete" value="<%= t('Delete') %>" />
|
57
|
+
<input class="btn btn-danger pull-right flip" type="submit" name="add_to_queue" value="<%= t('AddToQueue') %>" />
|
58
|
+
</form>
|
59
|
+
<% else %>
|
60
|
+
<div class="alert alert-success"><%= t('NoScheduledFound') %></div>
|
61
|
+
<% end %>
|
62
|
+
|
63
|
+
<div id="_sidekiq_web_block_screen_div_" style='display: none'>
|
64
|
+
<div id="_sidekiq_web_block_screen_text_"></div>
|
65
|
+
</div>
|
66
|
+
|
67
|
+
<script type="text/javascript">
|
68
|
+
function _sidekiq_web_block_screen(text) {
|
69
|
+
document.getElementById('_sidekiq_web_block_screen_text_').innerHTML = text
|
70
|
+
document.getElementById('_sidekiq_web_block_screen_div_').style.display = "block";
|
71
|
+
}
|
72
|
+
</script>
|
73
|
+
|
74
|
+
<style>
|
75
|
+
#_sidekiq_web_block_screen_div_ {
|
76
|
+
position: fixed;
|
77
|
+
display: none;
|
78
|
+
width: 100%;
|
79
|
+
height: 100%;
|
80
|
+
top: 0;
|
81
|
+
left: 0;
|
82
|
+
right: 0;
|
83
|
+
bottom: 0;
|
84
|
+
background-color: rgba(0,0,0,0.8);
|
85
|
+
z-index: 2;
|
86
|
+
}
|
87
|
+
|
88
|
+
#_sidekiq_web_block_screen_text_{
|
89
|
+
position: absolute;
|
90
|
+
top: 50%;
|
91
|
+
left: 50%;
|
92
|
+
font-size: 50px;
|
93
|
+
color: white;
|
94
|
+
transform: translate(-50%,-50%);
|
95
|
+
-ms-transform: translate(-50%,-50%);
|
96
|
+
}
|
97
|
+
</style>
|
@@ -0,0 +1,95 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'byebug'
|
4
|
+
require_relative 'web_custom/version'
|
5
|
+
|
6
|
+
# require sidekiq/web first to ensure web_Action will prepend correctly
|
7
|
+
require 'sidekiq/web'
|
8
|
+
require 'sidekiq/web_custom/configuration'
|
9
|
+
require 'sidekiq/web_custom/web_action'
|
10
|
+
require 'sidekiq/web_custom/queue'
|
11
|
+
require 'sidekiq/web_custom/job'
|
12
|
+
require 'sidekiq/web_custom/web_app'
|
13
|
+
|
14
|
+
module Sidekiq
|
15
|
+
module WebCustom
|
16
|
+
class Error < StandardError; end
|
17
|
+
class ArgumentError < Error; end
|
18
|
+
class FileNotFound < Error; end
|
19
|
+
class StopExecution < Error; end
|
20
|
+
class ExecutionTimeExceeded < Error; end
|
21
|
+
class ConfigurationEstablished < Error; end
|
22
|
+
|
23
|
+
BREAK_BIT = '__sidekiq-web_custom-breakbit__'
|
24
|
+
|
25
|
+
def self.default_available_actions_mapping
|
26
|
+
@available_actions_mapping ||= begin
|
27
|
+
temp = {}
|
28
|
+
Dir["#{actions_root}/**/*.erb"].map do |erb_path|
|
29
|
+
base_path = File.basename(erb_path).split('.')[0]
|
30
|
+
second_half = erb_path.split(actions_root)[1]
|
31
|
+
action_type = second_half.split(base_path)[0]
|
32
|
+
action_type = action_type.delete('/').to_sym
|
33
|
+
temp[action_type] ||= {}
|
34
|
+
temp[action_type][base_path.to_sym] = erb_path
|
35
|
+
end
|
36
|
+
temp
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.default_local_erb_mapping
|
41
|
+
@local_erb_mapping ||= Dir["#{local_erbs_root}/*.erb"].map do |erb_path|
|
42
|
+
[File.basename(erb_path).split('.')[0].to_sym, erb_path]
|
43
|
+
end.to_h
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.actions_root
|
47
|
+
@actions_root ||= "#{local_erbs_root}/actions"
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.local_erbs_root
|
51
|
+
@local_erbs_root ||= "#{root_path}/views"
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.root_path
|
55
|
+
@root_path ||= File.dirname(__FILE__)
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.config
|
59
|
+
@config ||= Configuration.new.tap do |t|
|
60
|
+
t.merge(base: :actions, params: default_available_actions_mapping)
|
61
|
+
t.merge(base: :local_erbs, params: default_local_erb_mapping)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.configure
|
66
|
+
yield config if block_given?
|
67
|
+
|
68
|
+
config.validate!
|
69
|
+
__inject_dependencies
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.local_erb_mapping
|
73
|
+
config.local_erbs
|
74
|
+
end
|
75
|
+
|
76
|
+
def self.reset!
|
77
|
+
@config = nil
|
78
|
+
end
|
79
|
+
|
80
|
+
private
|
81
|
+
|
82
|
+
def self.__inject_dependencies
|
83
|
+
return if @__already_called
|
84
|
+
|
85
|
+
@__already_called = true
|
86
|
+
::Sidekiq::WebAction.prepend WebAction
|
87
|
+
::Sidekiq::Queue.prepend Queue
|
88
|
+
::Sidekiq::Job.prepend Job
|
89
|
+
::Sidekiq::Web.register WebApp
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# dependent the error classes loaded on boot, requie after code is loaded
|
95
|
+
require 'sidekiq/web_custom/timeout'
|
@@ -0,0 +1,112 @@
|
|
1
|
+
module Sidekiq
|
2
|
+
module WebCustom
|
3
|
+
class Configuration
|
4
|
+
|
5
|
+
ALLOWED_BASED = [ACTIONS = :actions, LOCAL_ERBS = :local_erbs]
|
6
|
+
INTEGERS = [:drain_rate, :max_execution_time, :warn_execution_time]
|
7
|
+
|
8
|
+
DEFAULT_DRAIN_RATE = 10
|
9
|
+
DEFAULT_EXEC_TIME = 6
|
10
|
+
DEFAULT_WARN_TIME = 5
|
11
|
+
|
12
|
+
attr_reader *ALLOWED_BASED
|
13
|
+
attr_reader *INTEGERS
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
ALLOWED_BASED.each do |var|
|
17
|
+
instance_variable_set(:"@#{var}", {})
|
18
|
+
end
|
19
|
+
|
20
|
+
@drain_rate = DEFAULT_DRAIN_RATE
|
21
|
+
@max_execution_time = DEFAULT_EXEC_TIME
|
22
|
+
@warn_execution_time = DEFAULT_WARN_TIME
|
23
|
+
end
|
24
|
+
|
25
|
+
INTEGERS.each do |int|
|
26
|
+
self.define_method("#{int}=") do |val|
|
27
|
+
unless _allow_write_block?
|
28
|
+
raise Sidekiq::WebCustom::ConfigurationEstablished, "Unable to assign [#{int}]. Assignment must happen on boot"
|
29
|
+
end
|
30
|
+
|
31
|
+
unless [Integer, Float].include?(val.class)
|
32
|
+
raise Sidekiq::WebCustom::ArgumentError, "Expected #{int} to be an integer or float"
|
33
|
+
end
|
34
|
+
|
35
|
+
instance_variable_set(:"@#{int}", val)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def merge(base:, params:, action_type: nil)
|
40
|
+
unless _allow_write_block?
|
41
|
+
raise Sidekiq::WebCustom::ConfigurationEstablished, "Unable to assign base [#{base}]. Assignment must happen on boot"
|
42
|
+
end
|
43
|
+
raise Sidekiq::WebCustom::ArgumentError, "Unexpected base: #{base}" unless ALLOWED_BASED.include?(base)
|
44
|
+
raise Sidekiq::WebCustom::ArgumentError, "Expected object for #{base} to be a Hash" unless params.is_a?(Hash)
|
45
|
+
|
46
|
+
value = instance_variable_get(:"@#{base}")
|
47
|
+
value =
|
48
|
+
if action_type && base == ACTIONS
|
49
|
+
value[action_type.to_sym] ||= {}
|
50
|
+
value[action_type.to_sym].merge!(params)
|
51
|
+
value
|
52
|
+
else
|
53
|
+
value.merge(params)
|
54
|
+
end
|
55
|
+
instance_variable_set(:"@#{base}", value)
|
56
|
+
end
|
57
|
+
|
58
|
+
def validate!
|
59
|
+
ALLOWED_BASED.each do |key|
|
60
|
+
value = instance_variable_get(:"@#{key}")
|
61
|
+
|
62
|
+
_validate!(value, key)
|
63
|
+
end
|
64
|
+
|
65
|
+
unless @warn_execution_time <= @max_execution_time
|
66
|
+
raise Sidekiq::WebCustom::ArgumentError, "Expected warn_execution_time to be less than max_execution_time"
|
67
|
+
end
|
68
|
+
|
69
|
+
unless actions.keys.all? { |k| local_erbs.keys.include?(k) }
|
70
|
+
raise Sidekiq::WebCustom::ArgumentError, "Unexpected actions keys#{actions.keys} -- Expected to be part of #{local_erbs.keys}"
|
71
|
+
end
|
72
|
+
|
73
|
+
define_convenienve_methods!
|
74
|
+
_unset_allow_write!
|
75
|
+
end
|
76
|
+
|
77
|
+
private
|
78
|
+
|
79
|
+
def _allow_write_block?
|
80
|
+
true
|
81
|
+
end
|
82
|
+
|
83
|
+
def _unset_allow_write!
|
84
|
+
define_singleton_method('_allow_write_block?') do
|
85
|
+
false
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
def define_convenienve_methods!
|
90
|
+
actions.keys.each do |key|
|
91
|
+
define_singleton_method("actions_for_#{key.to_s}") do
|
92
|
+
actions[key]
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
def _validate!(params, key, add: [])
|
98
|
+
params.each do |k, file|
|
99
|
+
return _validate!(file, k, add: add << key) if file.is_a? Hash
|
100
|
+
passed = [add, k].flatten.compact.join(':')
|
101
|
+
|
102
|
+
|
103
|
+
next if File.exist?(file)
|
104
|
+
|
105
|
+
raise Sidekiq::WebCustom::FileNotFound,
|
106
|
+
"#{key}.merge passed #{passed}: #{file}.\n" \
|
107
|
+
"The absolute file path does not exist."
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
require 'sidekiq/processor'
|
2
|
+
|
3
|
+
module Sidekiq
|
4
|
+
module WebCustom
|
5
|
+
class Processor < ::Sidekiq::Processor
|
6
|
+
|
7
|
+
def self.execute(max:, queue:, options: Sidekiq.options)
|
8
|
+
__processor__(queue: queue, options: options).__execute(max: max)
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.execute_job(job:, options: Sidekiq.options)
|
12
|
+
__processor__(queue: job.queue, options: options).__execute_job(job: job)
|
13
|
+
rescue StandardError => _
|
14
|
+
false # error gets loggged downstream
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.__processor__(queue:, options: Sidekiq.options)
|
18
|
+
options_temp = options.clone
|
19
|
+
queue = queue.is_a?(String) ? Sidekiq::Queue.new(queue) : queue
|
20
|
+
|
21
|
+
options_temp[:queues] = [queue.name]
|
22
|
+
klass = options_temp[:fetch]&.class || BasicFetch
|
23
|
+
options_temp[:fetch] = klass.new(options_temp)
|
24
|
+
new(manager: nil, options: options_temp, queue: queue)
|
25
|
+
end
|
26
|
+
|
27
|
+
def initialize(manager:, options:, queue:)
|
28
|
+
@__queue = queue
|
29
|
+
@__basic_fetch = options[:fetch].class == BasicFetch
|
30
|
+
|
31
|
+
super(manager, options)
|
32
|
+
end
|
33
|
+
|
34
|
+
def __execute_job(job:)
|
35
|
+
queue_name = "queue:#{job.queue}"
|
36
|
+
work_unit = Sidekiq::BasicFetch::UnitOfWork.new(queue_name, job.item.to_json)
|
37
|
+
begin
|
38
|
+
Sidekiq.logger.info "Manually processing individual work unit for #{work_unit.queue_name}"
|
39
|
+
process(work_unit)
|
40
|
+
rescue StandardError => e
|
41
|
+
Sidekiq.logger.error "Manually processed work unit failed with #{e.message}. Work unit will not be dequeued"
|
42
|
+
raise e
|
43
|
+
end
|
44
|
+
|
45
|
+
begin
|
46
|
+
job.delete
|
47
|
+
Sidekiq.logger.info { "Manually processed work unit sucessfully dequeued." }
|
48
|
+
rescue StandardError => e
|
49
|
+
Sidekiq.logger.fatal "Manually processed work unit failed to be dequeued. #{e.message}."
|
50
|
+
raise e
|
51
|
+
end
|
52
|
+
|
53
|
+
true
|
54
|
+
end
|
55
|
+
|
56
|
+
def __execute(max:)
|
57
|
+
count = 0
|
58
|
+
max.times do
|
59
|
+
break if @__queue.size <= 0
|
60
|
+
|
61
|
+
if Thread.current[Sidekiq::WebCustom::BREAK_BIT]
|
62
|
+
Sidekiq.logger.warn "Yikes -- Break bit has been set. Attempting to return in time. Completed #{count} of attempted #{max}"
|
63
|
+
break
|
64
|
+
end
|
65
|
+
|
66
|
+
Sidekiq.logger.info { "Manually processing next item in queue:[#{@__queue.name}]" }
|
67
|
+
process_one
|
68
|
+
count += 1
|
69
|
+
|
70
|
+
end
|
71
|
+
count
|
72
|
+
rescue Exception => ex
|
73
|
+
if @job && @__basic_fetch
|
74
|
+
Sidekiq.logger.fatal "Processor Execution interrupted. Lost Job #{@job.job}"
|
75
|
+
end
|
76
|
+
Sidekiq.logger.warn "Manual execution has terminated. Received error [#{ex.message}]"
|
77
|
+
return count
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module Sidekiq
|
2
|
+
module WebCustom
|
3
|
+
module Timeout
|
4
|
+
module_function
|
5
|
+
DEFAULT_EXCEPTION = Sidekiq::WebCustom::ExecutionTimeExceeded
|
6
|
+
PROC = Proc.new do |warn_sec, timeout_sec, proc, exception, message, debug, &block|
|
7
|
+
puts "at: PROC; begining" if debug
|
8
|
+
|
9
|
+
sec_to_raise = timeout_sec - warn_sec
|
10
|
+
begin
|
11
|
+
from = debug ? "from #{caller_locations(1, 1)[0]}" : nil
|
12
|
+
x = Thread.current
|
13
|
+
# do everything in a new thread
|
14
|
+
y = Thread.start {
|
15
|
+
puts "at: PROC; second thread; about to start" if debug
|
16
|
+
Thread.current.name = from
|
17
|
+
# block for warning in new thread
|
18
|
+
begin
|
19
|
+
puts "at: PROC; second thread; starting warn time for #{warn_sec}'s " if debug
|
20
|
+
sleep warn_sec
|
21
|
+
rescue => e
|
22
|
+
x.raise e
|
23
|
+
else
|
24
|
+
# yield back during warning time so downstream can do some prep work
|
25
|
+
puts "at: PROC; second thread; trying to warn in main thread" if debug
|
26
|
+
proc.call(x, warn_sec)
|
27
|
+
end
|
28
|
+
|
29
|
+
# block additional seconds to raise for
|
30
|
+
begin
|
31
|
+
puts "at: PROC; second thread; starting violent exection time for #{sec_to_raise}'s " if debug
|
32
|
+
sleep sec_to_raise
|
33
|
+
rescue => e
|
34
|
+
puts "at: PROC; second thread; Error occured" if debug
|
35
|
+
x.raise e
|
36
|
+
else
|
37
|
+
puts "at: PROC; second thread; trying to raise in main thread" if debug
|
38
|
+
x.raise exception, message
|
39
|
+
end
|
40
|
+
}
|
41
|
+
puts "at: PROC; second thread; fully spooled" if debug
|
42
|
+
# after thread starts, yield back to calle function with max timout
|
43
|
+
block.call(timeout_sec)
|
44
|
+
ensure
|
45
|
+
if y
|
46
|
+
puts "at: PROC; Second thread still exists. Returned in time" if debug
|
47
|
+
y.kill
|
48
|
+
y.join
|
49
|
+
else
|
50
|
+
puts "at: PROC; Second thread no longer exists. Failed to return in time" if debug
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def timeout(warn:, timeout:, proc: ->(_, _) {}, exception: DEFAULT_EXCEPTION, message: nil, debug: false, &block)
|
56
|
+
raise Sidekiq::WebCustom::ArgumentError, 'Block not given' unless block_given?
|
57
|
+
|
58
|
+
puts "at: timeout; valid bock given" if debug
|
59
|
+
message ||= "Execution exceeded #{timeout} seconds." if debug
|
60
|
+
PROC.call(warn, timeout, proc, exception, message, debug, &block)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|