garcun 0.0.2
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/.gitattributes +17 -0
- data/.gitignore +197 -0
- data/.rspec +2 -0
- data/Gemfile +22 -0
- data/LICENSE +201 -0
- data/README.md +521 -0
- data/Rakefile +47 -0
- data/garcun.gemspec +83 -0
- data/lib/garcon.rb +290 -0
- data/lib/garcon/chef/chef_helpers.rb +343 -0
- data/lib/garcon/chef/coerce/coercer.rb +134 -0
- data/lib/garcon/chef/coerce/coercions/boolean_definitions.rb +34 -0
- data/lib/garcon/chef/coerce/coercions/date_definitions.rb +32 -0
- data/lib/garcon/chef/coerce/coercions/date_time_definitions.rb +32 -0
- data/lib/garcon/chef/coerce/coercions/fixnum_definitions.rb +34 -0
- data/lib/garcon/chef/coerce/coercions/float_definitions.rb +32 -0
- data/lib/garcon/chef/coerce/coercions/hash_definitions.rb +29 -0
- data/lib/garcon/chef/coerce/coercions/integer_definitions.rb +31 -0
- data/lib/garcon/chef/coerce/coercions/string_definitions.rb +45 -0
- data/lib/garcon/chef/coerce/coercions/time_definitions.rb +32 -0
- data/lib/garcon/chef/handler/devreporter.rb +127 -0
- data/lib/garcon/chef/log.rb +64 -0
- data/lib/garcon/chef/node.rb +100 -0
- data/lib/garcon/chef/provider/civilize.rb +209 -0
- data/lib/garcon/chef/provider/development.rb +159 -0
- data/lib/garcon/chef/provider/download.rb +420 -0
- data/lib/garcon/chef/provider/house_keeping.rb +265 -0
- data/lib/garcon/chef/provider/node_cache.rb +31 -0
- data/lib/garcon/chef/provider/partial.rb +183 -0
- data/lib/garcon/chef/provider/recovery.rb +80 -0
- data/lib/garcon/chef/provider/zip_file.rb +271 -0
- data/lib/garcon/chef/resource/attribute.rb +52 -0
- data/lib/garcon/chef/resource/base_dsl.rb +174 -0
- data/lib/garcon/chef/resource/blender.rb +140 -0
- data/lib/garcon/chef/resource/lazy_eval.rb +66 -0
- data/lib/garcon/chef/resource/resource_name.rb +109 -0
- data/lib/garcon/chef/secret_bag.rb +204 -0
- data/lib/garcon/chef/validations.rb +76 -0
- data/lib/garcon/chef_inclusions.rb +151 -0
- data/lib/garcon/configuration.rb +138 -0
- data/lib/garcon/core_ext.rb +39 -0
- data/lib/garcon/core_ext/array.rb +27 -0
- data/lib/garcon/core_ext/binding.rb +64 -0
- data/lib/garcon/core_ext/boolean.rb +66 -0
- data/lib/garcon/core_ext/duration.rb +271 -0
- data/lib/garcon/core_ext/enumerable.rb +34 -0
- data/lib/garcon/core_ext/file.rb +127 -0
- data/lib/garcon/core_ext/filetest.rb +62 -0
- data/lib/garcon/core_ext/hash.rb +279 -0
- data/lib/garcon/core_ext/kernel.rb +159 -0
- data/lib/garcon/core_ext/lazy.rb +222 -0
- data/lib/garcon/core_ext/method_access.rb +243 -0
- data/lib/garcon/core_ext/module.rb +92 -0
- data/lib/garcon/core_ext/nil.rb +53 -0
- data/lib/garcon/core_ext/numeric.rb +44 -0
- data/lib/garcon/core_ext/object.rb +342 -0
- data/lib/garcon/core_ext/pathname.rb +152 -0
- data/lib/garcon/core_ext/process.rb +41 -0
- data/lib/garcon/core_ext/random.rb +497 -0
- data/lib/garcon/core_ext/string.rb +312 -0
- data/lib/garcon/core_ext/struct.rb +49 -0
- data/lib/garcon/core_ext/symbol.rb +170 -0
- data/lib/garcon/core_ext/time.rb +234 -0
- data/lib/garcon/exceptions.rb +101 -0
- data/lib/garcon/inflections.rb +237 -0
- data/lib/garcon/inflections/defaults.rb +79 -0
- data/lib/garcon/inflections/inflections.rb +182 -0
- data/lib/garcon/inflections/rules_collection.rb +37 -0
- data/lib/garcon/secret.rb +271 -0
- data/lib/garcon/stash/format.rb +114 -0
- data/lib/garcon/stash/journal.rb +226 -0
- data/lib/garcon/stash/queue.rb +83 -0
- data/lib/garcon/stash/serializer.rb +86 -0
- data/lib/garcon/stash/store.rb +435 -0
- data/lib/garcon/task.rb +31 -0
- data/lib/garcon/task/atomic.rb +151 -0
- data/lib/garcon/task/atomic_boolean.rb +127 -0
- data/lib/garcon/task/condition.rb +99 -0
- data/lib/garcon/task/copy_on_notify_observer_set.rb +154 -0
- data/lib/garcon/task/copy_on_write_observer_set.rb +153 -0
- data/lib/garcon/task/count_down_latch.rb +92 -0
- data/lib/garcon/task/delay.rb +196 -0
- data/lib/garcon/task/dereferenceable.rb +144 -0
- data/lib/garcon/task/event.rb +119 -0
- data/lib/garcon/task/executor.rb +275 -0
- data/lib/garcon/task/executor_options.rb +59 -0
- data/lib/garcon/task/future.rb +107 -0
- data/lib/garcon/task/immediate_executor.rb +84 -0
- data/lib/garcon/task/ivar.rb +171 -0
- data/lib/garcon/task/lazy_reference.rb +74 -0
- data/lib/garcon/task/monotonic_time.rb +69 -0
- data/lib/garcon/task/obligation.rb +256 -0
- data/lib/garcon/task/observable.rb +101 -0
- data/lib/garcon/task/priority_queue.rb +234 -0
- data/lib/garcon/task/processor_count.rb +128 -0
- data/lib/garcon/task/read_write_lock.rb +304 -0
- data/lib/garcon/task/safe_task_executor.rb +58 -0
- data/lib/garcon/task/single_thread_executor.rb +97 -0
- data/lib/garcon/task/thread_pool/cached.rb +71 -0
- data/lib/garcon/task/thread_pool/executor.rb +294 -0
- data/lib/garcon/task/thread_pool/fixed.rb +61 -0
- data/lib/garcon/task/thread_pool/worker.rb +90 -0
- data/lib/garcon/task/timer.rb +44 -0
- data/lib/garcon/task/timer_set.rb +194 -0
- data/lib/garcon/task/timer_task.rb +377 -0
- data/lib/garcon/task/waitable_list.rb +58 -0
- data/lib/garcon/utility/ansi.rb +199 -0
- data/lib/garcon/utility/at_random.rb +77 -0
- data/lib/garcon/utility/crypto.rb +292 -0
- data/lib/garcon/utility/equalizer.rb +146 -0
- data/lib/garcon/utility/faker/extensions/array.rb +22 -0
- data/lib/garcon/utility/faker/extensions/symbol.rb +9 -0
- data/lib/garcon/utility/faker/faker.rb +164 -0
- data/lib/garcon/utility/faker/faker/company.rb +17 -0
- data/lib/garcon/utility/faker/faker/hacker.rb +30 -0
- data/lib/garcon/utility/faker/faker/version.rb +3 -0
- data/lib/garcon/utility/faker/locales/en-US.yml +83 -0
- data/lib/garcon/utility/faker/locales/en.yml +21 -0
- data/lib/garcon/utility/file_helper.rb +170 -0
- data/lib/garcon/utility/hookers.rb +178 -0
- data/lib/garcon/utility/interpolation.rb +90 -0
- data/lib/garcon/utility/memstash.rb +364 -0
- data/lib/garcon/utility/misc.rb +54 -0
- data/lib/garcon/utility/msg_from_god.rb +62 -0
- data/lib/garcon/utility/retry.rb +238 -0
- data/lib/garcon/utility/timeout.rb +58 -0
- data/lib/garcon/utility/uber/builder.rb +91 -0
- data/lib/garcon/utility/uber/callable.rb +7 -0
- data/lib/garcon/utility/uber/delegates.rb +13 -0
- data/lib/garcon/utility/uber/inheritable_attr.rb +37 -0
- data/lib/garcon/utility/uber/options.rb +101 -0
- data/lib/garcon/utility/uber/uber_version.rb +3 -0
- data/lib/garcon/utility/uber/version.rb +33 -0
- data/lib/garcon/utility/url_helper.rb +100 -0
- data/lib/garcon/utils.rb +29 -0
- data/lib/garcon/version.rb +62 -0
- data/lib/garcun.rb +24 -0
- metadata +680 -0
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
#
|
|
3
|
+
# Author: Stefano Harding <riddopic@gmail.com>
|
|
4
|
+
# License: Apache License, Version 2.0
|
|
5
|
+
# Copyright: (C) 2014-2015 Stefano Harding
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
# you may not use this file except in compliance with the License.
|
|
9
|
+
# You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
# See the License for the specific language governing permissions and
|
|
17
|
+
# limitations under the License.
|
|
18
|
+
#
|
|
19
|
+
|
|
20
|
+
require_relative 'executor'
|
|
21
|
+
|
|
22
|
+
module Garcon
|
|
23
|
+
|
|
24
|
+
class RubySingleThreadExecutor
|
|
25
|
+
include RubyExecutor
|
|
26
|
+
include SerialExecutor
|
|
27
|
+
|
|
28
|
+
# Create a new thread pool.
|
|
29
|
+
#
|
|
30
|
+
# @option opts [Symbol] :fallback_policy (:discard)
|
|
31
|
+
# The policy for handling new tasks that are received when the queue size
|
|
32
|
+
# has reached `max_queue` or after the executor has shut down.
|
|
33
|
+
#
|
|
34
|
+
def initialize(opts = {})
|
|
35
|
+
@queue = Queue.new
|
|
36
|
+
@thread = nil
|
|
37
|
+
@fallback_policy = opts.fetch(:fallback_policy, :discard)
|
|
38
|
+
if !FALLBACK_POLICY.include?(fallback)
|
|
39
|
+
raise ArgumentError, "#{fallback} is not a valid fallback policy"
|
|
40
|
+
end
|
|
41
|
+
init_executor
|
|
42
|
+
enable_at_exit_handler!(opts)
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
protected # A T T E N Z I O N E A R E A P R O T E T T A
|
|
46
|
+
|
|
47
|
+
# @!visibility private
|
|
48
|
+
def execute(*args, &task)
|
|
49
|
+
supervise
|
|
50
|
+
@queue << [args, task]
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# @!visibility private
|
|
54
|
+
def shutdown_execution
|
|
55
|
+
@queue << :stop
|
|
56
|
+
stopped_event.set unless alive?
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
# @!visibility private
|
|
60
|
+
def kill_execution
|
|
61
|
+
@queue.clear
|
|
62
|
+
@thread.kill if alive?
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# @!visibility private
|
|
66
|
+
def alive?
|
|
67
|
+
@thread && @thread.alive?
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# @!visibility private
|
|
71
|
+
def supervise
|
|
72
|
+
@thread = new_worker_thread unless alive?
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
# @!visibility private
|
|
76
|
+
def new_worker_thread
|
|
77
|
+
Thread.new do
|
|
78
|
+
Thread.current.abort_on_exception = false
|
|
79
|
+
work
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
# @!visibility private
|
|
84
|
+
def work
|
|
85
|
+
loop do
|
|
86
|
+
task = @queue.pop
|
|
87
|
+
break if task == :stop
|
|
88
|
+
begin
|
|
89
|
+
task.last.call(*task.first)
|
|
90
|
+
rescue => e
|
|
91
|
+
Chef::Log.debug "Caught exception => #{e}"
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
stopped_event.set
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
#
|
|
3
|
+
# Author: Stefano Harding <riddopic@gmail.com>
|
|
4
|
+
# License: Apache License, Version 2.0
|
|
5
|
+
# Copyright: (C) 2014-2015 Stefano Harding
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
# you may not use this file except in compliance with the License.
|
|
9
|
+
# You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
# See the License for the specific language governing permissions and
|
|
17
|
+
# limitations under the License.
|
|
18
|
+
#
|
|
19
|
+
|
|
20
|
+
require_relative 'executor'
|
|
21
|
+
|
|
22
|
+
module Garcon
|
|
23
|
+
|
|
24
|
+
# A thread pool that dynamically grows and shrinks to fit the current
|
|
25
|
+
# workload. New threads are created as needed, existing threads are reused,
|
|
26
|
+
# and threads that remain idle for too long are killed and removed from the
|
|
27
|
+
# pool. These pools are particularly suited to applications that perform a
|
|
28
|
+
# high volume of short-lived tasks.
|
|
29
|
+
#
|
|
30
|
+
# On creation a `CachedThreadPool` has zero running threads. New threads are
|
|
31
|
+
# created on the pool as new operations are `#post`. The size of the pool
|
|
32
|
+
# will grow until `#max_length` threads are in the pool or until the number
|
|
33
|
+
# of threads exceeds the number of running and pending operations. When a new
|
|
34
|
+
# operation is post to the pool the first available idle thread will be
|
|
35
|
+
# tasked with the new operation.
|
|
36
|
+
#
|
|
37
|
+
# Should a thread crash for any reason the thread will immediately be removed
|
|
38
|
+
# from the pool. Similarly, threads which remain idle for an extended period
|
|
39
|
+
# of time will be killed and reclaimed. Thus these thread pools are very
|
|
40
|
+
# efficient at reclaiming unused resources.
|
|
41
|
+
#
|
|
42
|
+
class CachedThreadPool < ThreadPoolExecutor
|
|
43
|
+
# Create a new thread pool.
|
|
44
|
+
#
|
|
45
|
+
# @param [Hash] opts
|
|
46
|
+
# The options defining pool behavior.
|
|
47
|
+
#
|
|
48
|
+
# @raise [ArgumentError] if `fallback` is not a known policy
|
|
49
|
+
#
|
|
50
|
+
# @option opts [Symbol] :fallback (`:abort`)
|
|
51
|
+
# The fallback policy
|
|
52
|
+
#
|
|
53
|
+
# @api public
|
|
54
|
+
def initialize(opts = {})
|
|
55
|
+
fallback = opts.fetch(:fallback, :abort)
|
|
56
|
+
|
|
57
|
+
unless FALLBACK_POLICY.include?(fallback)
|
|
58
|
+
raise ArgumentError, "#{fallback} is not a valid fallback policy"
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
opts = opts.merge(
|
|
62
|
+
min_threads: 0,
|
|
63
|
+
max_threads: DEFAULT_MAX_POOL_SIZE,
|
|
64
|
+
fallback: fallback,
|
|
65
|
+
max_queue: DEFAULT_MAX_QUEUE_SIZE,
|
|
66
|
+
idletime: DEFAULT_THREAD_IDLETIMEOUT)
|
|
67
|
+
|
|
68
|
+
super(opts)
|
|
69
|
+
end
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,294 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
#
|
|
3
|
+
# Author: Stefano Harding <riddopic@gmail.com>
|
|
4
|
+
# License: Apache License, Version 2.0
|
|
5
|
+
# Copyright: (C) 2014-2015 Stefano Harding
|
|
6
|
+
#
|
|
7
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
8
|
+
# you may not use this file except in compliance with the License.
|
|
9
|
+
# You may obtain a copy of the License at
|
|
10
|
+
#
|
|
11
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
12
|
+
#
|
|
13
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
14
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
15
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
16
|
+
# See the License for the specific language governing permissions and
|
|
17
|
+
# limitations under the License.
|
|
18
|
+
#
|
|
19
|
+
|
|
20
|
+
require 'thread'
|
|
21
|
+
require_relative 'worker'
|
|
22
|
+
require_relative '../event'
|
|
23
|
+
require_relative '../executor'
|
|
24
|
+
require_relative '../monotonic_time'
|
|
25
|
+
|
|
26
|
+
module Garcon
|
|
27
|
+
|
|
28
|
+
class ThreadPoolExecutor
|
|
29
|
+
include RubyExecutor
|
|
30
|
+
|
|
31
|
+
# Default maximum number of threads that will be created in the pool.
|
|
32
|
+
DEFAULT_MAX_POOL_SIZE = 2**15 # 32768
|
|
33
|
+
|
|
34
|
+
# Default minimum number of threads that will be retained in the pool.
|
|
35
|
+
DEFAULT_MIN_POOL_SIZE = 0
|
|
36
|
+
|
|
37
|
+
# Default maximum number of tasks that may be added to the task queue.
|
|
38
|
+
DEFAULT_MAX_QUEUE_SIZE = 0
|
|
39
|
+
|
|
40
|
+
# Default maximum number of seconds a thread in the pool may remain idle
|
|
41
|
+
# before being reclaimed.
|
|
42
|
+
DEFAULT_THREAD_IDLETIMEOUT = 60
|
|
43
|
+
|
|
44
|
+
# The maximum number of threads that may be created in the pool.
|
|
45
|
+
attr_reader :max_length
|
|
46
|
+
|
|
47
|
+
# The minimum number of threads that may be retained in the pool.
|
|
48
|
+
attr_reader :min_length
|
|
49
|
+
|
|
50
|
+
# The largest number of threads that have been created in the pool since
|
|
51
|
+
# construction.
|
|
52
|
+
attr_reader :largest_length
|
|
53
|
+
|
|
54
|
+
# The number of tasks that have been scheduled for execution on the pool
|
|
55
|
+
# since construction.
|
|
56
|
+
attr_reader :scheduled_task_count
|
|
57
|
+
|
|
58
|
+
# The number of tasks that have been completed by the pool since
|
|
59
|
+
# construction.
|
|
60
|
+
attr_reader :completed_task_count
|
|
61
|
+
|
|
62
|
+
# The number of seconds that a thread may be idle before being reclaimed.
|
|
63
|
+
attr_reader :idletime
|
|
64
|
+
|
|
65
|
+
# The maximum number of tasks that may be waiting in the work queue at any
|
|
66
|
+
# one time. When the queue size reaches `max_queue` subsequent tasks will be
|
|
67
|
+
# rejected in accordance with the configured `fallback`.
|
|
68
|
+
attr_reader :max_queue
|
|
69
|
+
|
|
70
|
+
# Create a new thread pool.
|
|
71
|
+
#
|
|
72
|
+
# @param [Hash] opts
|
|
73
|
+
# The options which configure the thread pool.
|
|
74
|
+
#
|
|
75
|
+
# @option opts [Integer] :max_threads (DEFAULT_MAX_POOL_SIZE)
|
|
76
|
+
# The maximum number of threads to be created.
|
|
77
|
+
#
|
|
78
|
+
# @option opts [Integer] :min_threads (DEFAULT_MIN_POOL_SIZE)
|
|
79
|
+
# The minimum number of threads to be retained.
|
|
80
|
+
#
|
|
81
|
+
# @option opts [Integer] :idletime (DEFAULT_THREAD_IDLETIMEOUT)
|
|
82
|
+
# Maximum number of seconds a thread may be idle before being reclaimed.
|
|
83
|
+
#
|
|
84
|
+
# @option opts [Integer] :max_queue (DEFAULT_MAX_QUEUE_SIZE)
|
|
85
|
+
# The maximum number of tasks allowed in the work queue at any one time;
|
|
86
|
+
# a value of zero means the queue may grow without bound.
|
|
87
|
+
#
|
|
88
|
+
# @option opts [Symbol] :fallback (:abort)
|
|
89
|
+
# The policy for handling new tasks that are received when the queue size
|
|
90
|
+
# has reached `max_queue` or the executor has shut down.
|
|
91
|
+
#
|
|
92
|
+
# @raise [ArgumentError] if `:max_threads` is less than one
|
|
93
|
+
#
|
|
94
|
+
# @raise [ArgumentError] if `:min_threads` is less than zero
|
|
95
|
+
#
|
|
96
|
+
# @raise [ArgumentError] if `:fallback` is not one of the values specified
|
|
97
|
+
# in `FALLBACK_POLICY`
|
|
98
|
+
#
|
|
99
|
+
def initialize(opts = {})
|
|
100
|
+
@min_length = opts.fetch(:min_threads, DEFAULT_MIN_POOL_SIZE).to_i
|
|
101
|
+
@max_length = opts.fetch(:max_threads, DEFAULT_MAX_POOL_SIZE).to_i
|
|
102
|
+
@idletime = opts.fetch(:idletime, DEFAULT_THREAD_IDLETIMEOUT).to_i
|
|
103
|
+
@max_queue = opts.fetch(:max_queue, DEFAULT_MAX_QUEUE_SIZE).to_i
|
|
104
|
+
@fallback = opts.fetch(:fallback, :abort)
|
|
105
|
+
|
|
106
|
+
if @max_length <= 0
|
|
107
|
+
raise ArgumentError, 'max_threads must be greater than zero'
|
|
108
|
+
elsif @min_length < 0
|
|
109
|
+
raise ArgumentError, 'min_threads cannot be less than zero'
|
|
110
|
+
elsif min_length > max_length
|
|
111
|
+
raise ArgumentError, 'min_threads cannot be more than max_threads'
|
|
112
|
+
elsif !FALLBACK_POLICY.include?(@fallback)
|
|
113
|
+
raise ArgumentError, "#{fallback} is not a valid fallback policy"
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
init_executor
|
|
117
|
+
enable_at_exit_handler!(opts)
|
|
118
|
+
|
|
119
|
+
@pool = []
|
|
120
|
+
@queue = Queue.new
|
|
121
|
+
@scheduled_task_count = 0
|
|
122
|
+
@completed_task_count = 0
|
|
123
|
+
@largest_length = 0
|
|
124
|
+
|
|
125
|
+
@gc_interval = opts.fetch(:gc_interval, 1).to_i
|
|
126
|
+
@last_gc_time = Garcon.monotonic_time - [1.0, (@gc_interval * 2.0)].max
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
# @!macro executor_module_method_can_overflow_question
|
|
130
|
+
def can_overflow?
|
|
131
|
+
@max_queue != 0
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# The number of threads currently in the pool.
|
|
135
|
+
#
|
|
136
|
+
# @return [Integer] the length
|
|
137
|
+
def length
|
|
138
|
+
mutex.synchronize { running? ? @pool.length : 0 }
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
alias_method :current_length, :length
|
|
142
|
+
|
|
143
|
+
# The number of tasks in the queue awaiting execution.
|
|
144
|
+
#
|
|
145
|
+
# @return [Integer] the queue_length
|
|
146
|
+
def queue_length
|
|
147
|
+
mutex.synchronize { running? ? @queue.length : 666 }
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
# Returns an array with the status of each thread in the pool
|
|
151
|
+
#
|
|
152
|
+
def status
|
|
153
|
+
mutex.synchronize { @pool.collect { |worker| worker.status } }
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Number of tasks that may be enqueued before reaching `max_queue` and
|
|
157
|
+
# rejecting new tasks. A value of -1 indicates that the queue may grow
|
|
158
|
+
# without bound.
|
|
159
|
+
#
|
|
160
|
+
# @return [Integer] the remaining_capacity
|
|
161
|
+
def remaining_capacity
|
|
162
|
+
mutex.synchronize { @max_queue == 0 ? -1 : @max_queue - @queue.length }
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
# Run on task completion.
|
|
166
|
+
#
|
|
167
|
+
# @!visibility private
|
|
168
|
+
def on_end_task
|
|
169
|
+
mutex.synchronize do
|
|
170
|
+
@completed_task_count += 1 #if success
|
|
171
|
+
break unless running?
|
|
172
|
+
end
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
# Run when a thread worker exits.
|
|
176
|
+
#
|
|
177
|
+
# @!visibility private
|
|
178
|
+
def on_worker_exit(worker)
|
|
179
|
+
mutex.synchronize do
|
|
180
|
+
@pool.delete(worker)
|
|
181
|
+
if @pool.empty? && !running?
|
|
182
|
+
stop_event.set
|
|
183
|
+
stopped_event.set
|
|
184
|
+
end
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
protected # A T T E N Z I O N E A R E A P R O T E T T A
|
|
189
|
+
|
|
190
|
+
# @!visibility private
|
|
191
|
+
def execute(*args, &task)
|
|
192
|
+
if ensure_capacity?
|
|
193
|
+
@scheduled_task_count += 1
|
|
194
|
+
@queue << [args, task]
|
|
195
|
+
else
|
|
196
|
+
if @max_queue != 0 && @queue.length >= @max_queue
|
|
197
|
+
handle_fallback(*args, &task)
|
|
198
|
+
end
|
|
199
|
+
end
|
|
200
|
+
prune_pool
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
# @!visibility private
|
|
204
|
+
def shutdown_execution
|
|
205
|
+
if @pool.empty?
|
|
206
|
+
stopped_event.set
|
|
207
|
+
else
|
|
208
|
+
@pool.length.times { @queue << :stop }
|
|
209
|
+
end
|
|
210
|
+
end
|
|
211
|
+
|
|
212
|
+
# @!visibility private
|
|
213
|
+
def kill_execution
|
|
214
|
+
@queue.clear
|
|
215
|
+
drain_pool
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
# Check the thread pool configuration and determine if the pool
|
|
219
|
+
# has enought capacity to handle the request. Will grow the size
|
|
220
|
+
# of the pool if necessary.
|
|
221
|
+
#
|
|
222
|
+
# @return [Boolean] true if the pool has enough capacity else false
|
|
223
|
+
#
|
|
224
|
+
# @!visibility private
|
|
225
|
+
def ensure_capacity?
|
|
226
|
+
additional = 0
|
|
227
|
+
capacity = true
|
|
228
|
+
|
|
229
|
+
if @pool.size < @min_length
|
|
230
|
+
additional = @min_length - @pool.size
|
|
231
|
+
elsif @queue.empty? && @queue.num_waiting >= 1
|
|
232
|
+
additional = 0
|
|
233
|
+
elsif @pool.size == 0 && @min_length == 0
|
|
234
|
+
additional = 1
|
|
235
|
+
elsif @pool.size < @max_length || @max_length == 0
|
|
236
|
+
additional = 1
|
|
237
|
+
elsif @max_queue == 0 || @queue.size < @max_queue
|
|
238
|
+
additional = 0
|
|
239
|
+
else
|
|
240
|
+
capacity = false
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
additional.times do
|
|
244
|
+
@pool << create_worker_thread
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
if additional > 0
|
|
248
|
+
@largest_length = [@largest_length, @pool.length].max
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
capacity
|
|
252
|
+
end
|
|
253
|
+
|
|
254
|
+
# Scan all threads in the pool and reclaim any that are dead or
|
|
255
|
+
# have been idle too long. Will check the last time the pool was
|
|
256
|
+
# pruned and only run if the configured garbage collection
|
|
257
|
+
# interval has passed.
|
|
258
|
+
#
|
|
259
|
+
# @!visibility private
|
|
260
|
+
def prune_pool
|
|
261
|
+
if Garcon.monotonic_time - @gc_interval >= @last_gc_time
|
|
262
|
+
@pool.delete_if { |worker| worker.dead? }
|
|
263
|
+
# send :stop for each thread over idletime
|
|
264
|
+
@pool.select { |worker| @idletime != 0 &&
|
|
265
|
+
Garcon.monotonic_time - @idletime > worker.last_activity
|
|
266
|
+
}.each { @queue << :stop }
|
|
267
|
+
@last_gc_time = Garcon.monotonic_time
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
# Reclaim all threads in the pool.
|
|
272
|
+
#
|
|
273
|
+
# @!visibility private
|
|
274
|
+
def drain_pool
|
|
275
|
+
@pool.each { |worker| worker.kill }
|
|
276
|
+
@pool.clear
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
# Create a single worker thread to be added to the pool.
|
|
280
|
+
#
|
|
281
|
+
# @return [Thread] the new thread.
|
|
282
|
+
#
|
|
283
|
+
# @!visibility private
|
|
284
|
+
def create_worker_thread
|
|
285
|
+
wrkr = ThreadPoolWorker.new(@queue, self)
|
|
286
|
+
Thread.new(wrkr, self) do |worker, parent|
|
|
287
|
+
Thread.current.abort_on_exception = false
|
|
288
|
+
worker.run
|
|
289
|
+
parent.on_worker_exit(worker)
|
|
290
|
+
end
|
|
291
|
+
return wrkr
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
end
|