parallel_minion 0.0.1 → 0.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a490fae075880a809d3d3542381454e2737ee560
4
- data.tar.gz: bec1bb591e8d19b490821f5153cb195083e9e58a
3
+ metadata.gz: ba4bc73da8594cb544d75365ae616634584cb197
4
+ data.tar.gz: 14a7ccfde7406ba6f41b0c28b133fb989160c67f
5
5
  SHA512:
6
- metadata.gz: 49c1e58bcb4011633cd0f80d666a6872f8fea1719cb5e2085dc463e6afd0ed71672ee1e49c5846fca668a0704beebdf22f0b816d804a7590f88e02571bf7ecd6
7
- data.tar.gz: 383505b36f1990379463117143231f2c069dc3451658a05fcc8d5c303a1394cdf76a232a4439f0d90660e8af3305ddc6445f5c74171f75f70940df7f0f43f534
6
+ metadata.gz: d9dca76b499fa4484575825bfe0e7a86feb49e3a46f921e1a34211c5db4bca6506ad3456a947b1423a8914fb0f371f29443bbd465d7db5525bae1c4b40f97ca6
7
+ data.tar.gz: 571076e7b09162becba4c8d1c8a79f3f568722b6f276798cbaf5f97cae8abff608c778ec6d0289e9ecc1c931a17bb8dc788f1170a7191e31377b2d989eb66b9e
data/README.md CHANGED
@@ -1,49 +1,67 @@
1
1
  parallel_minion
2
2
  ===============
3
3
 
4
- Parallel Minion supports easily handing work off to Minions (Threads) so that tasks
4
+ Parallel Minion supports easily handing work off to minions (threads) so that tasks
5
5
  that would normally be performed sequentially can easily be executed in parallel.
6
6
  This allows Ruby and Rails applications to very easily do many tasks at the same
7
7
  time so that results are returned more quickly.
8
8
 
9
- Our use-case for Minions is where an application grew to a point where it would
9
+ Our use-case for minions is where an application grew to a point where it would
10
10
  be useful to run some of the steps in fulfilling a single request in parallel.
11
11
 
12
12
  ## Features:
13
13
 
14
14
  Exceptions
15
15
 
16
- - Any exceptions raised in Minions are captured and propagated back to the
16
+ - Any exceptions raised in minions are captured and propagated back to the
17
17
  calling thread when #result is called
18
- - Makes exception handling simple with a drop-in replacement in existing code
18
+ - Makes exception handling simple with a drop-in replacement for existing code
19
+ - Avoids having to implement more complex actors and supervisors required
20
+ by some concurrency frameworks
19
21
 
20
22
  Timeouts
21
23
 
22
- - Timeout when a Minion does not return within a specified time
23
- - Timeouts are a useful feature when one of the Minions fails to respond in a
24
+ - Timeout when a minion does not return within a specified time
25
+ - Timeouts are a useful feature when one of the minions fails to respond in a
24
26
  reasonable amount of time. For example when a call to a remote service hangs
25
27
  we can send back a partial response of other work that was completed rather
26
28
  than just "hanging" or failing completely.
27
29
 
28
30
  Logging
29
31
 
30
- - Built-in support to log the duration of all Minion tasks to make future analysis
32
+ - Built-in support to log the duration of all minion tasks to make future analysis
31
33
  of performance issues much easier
32
- - Logs any exceptions thrown to assist fwith problem diagnosis
34
+ - Logs any exceptions thrown to assist with problem diagnosis
35
+ - Logging tags from the current thread are propagated to the minions thread
36
+ - The name of the thread in log entries is set to the description supplied for
37
+ the minion to make it easy to distinguish log entries by minion / thread
38
+
39
+ Rails Support
40
+
41
+ - When used in a Rails environment the current scope of specified models can be
42
+ propagated to the minions thread
33
43
 
34
44
  ## Example
35
45
 
36
46
  Simple example
37
47
 
38
48
  ```ruby
39
- ParallelMinion::Minion.new(10.days.ago, description: 'Doing something else in parallel', timeout: 1000) do |date|
49
+ minion = ParallelMinion::Minion.new(10.days.ago, description: 'Doing something else in parallel', timeout: 1000) do |date|
40
50
  MyTable.where('created_at <= ?', date).count
41
51
  end
52
+
53
+ # Do other work here...
54
+
55
+ # Retrieve the result of the minion
56
+ count = minion.result
57
+
58
+ puts "Found #{count} records"
42
59
  ```
43
60
 
44
61
  ## Example
45
62
 
46
- For example, in the code below there are several steps that are performed sequentially:
63
+ For example, in the code below there are several steps that are performed
64
+ sequentially and does not yet use minions:
47
65
 
48
66
  ```ruby
49
67
  # Contrived example to show how to do parallel code execution
@@ -190,13 +208,39 @@ end
190
208
 
191
209
  The above #process_request method should now take on average 1,810 milli-seconds
192
210
  which is significantly faster than the 3,780 milli-seconds it took to perform
193
- the exact same request, but using only a single thread
211
+ the exact same request prior to using minions.
194
212
 
195
- The exact breakdown of which calls to do in the main thread versus a Minion is determined
213
+ The exact breakdown of which calls to do in the main thread versus a minion is determined
196
214
  through experience and trial and error over time. The key is logging the duration
197
- of each call which Minion does by default so that the exact processing breakdown
215
+ of each call which minion does by default so that the exact processing breakdown
198
216
  can be fine-tuned over time.
199
217
 
218
+ ## Disabling Minions
219
+
220
+ In the event that strange problems are occurring in production and no one is
221
+ sure if it is due to running the minion tasks in parallel, it is simple to make
222
+ all minion tasks run in the calling thread.
223
+
224
+ It may also be useful to disable minions on a single production server to compare
225
+ its performance to that of the servers running with minions active.
226
+
227
+ To disable minions / make them run in the calling thread, add the following
228
+ lines to config/environments/production.rb:
229
+
230
+ ```ruby
231
+ # Make minions run immediately in the current thread
232
+ config.parallel_minion.enabled = false
233
+ ```
234
+
235
+ ## Notes:
236
+
237
+ - When using JRuby it is important to enable it's built-in thread-pooling by
238
+ adding the following line to .jrubyrc, or setting the appropriate command line option:
239
+
240
+ ```ruby
241
+ thread.pool.enabled=true
242
+ ```
243
+
200
244
  Meta
201
245
  ----
202
246
 
@@ -15,24 +15,23 @@ module ParallelMinion
15
15
  # Give an infinite amount of time to wait for a Minion to complete a task
16
16
  INFINITE = -1
17
17
 
18
- # Sets whether to run in Synchronous mode
18
+ # Sets whether minions are enabled to run in their own threads
19
19
  #
20
- # By Setting synchronous to true all Minions that have not yet been started
21
- # will run in the thread from which they are started and not in their own
22
- # threads
20
+ # By Setting _enabled_ to false all Minions that have not yet been started
21
+ # will run in the thread from which it is created and not on its own thread
23
22
  #
24
23
  # This is useful:
25
24
  # - to run tests under the Capybara gem
26
25
  # - when debugging code so that all code is run sequentially in the current thread
27
26
  #
28
- # Note: Do not set this setting to true in Production
29
- def self.synchronous=(synchronous)
30
- @@synchronous = synchronous
27
+ # Note: Not recommended to set this setting to false in Production
28
+ def self.enabled=(enabled)
29
+ @@enabled = enabled
31
30
  end
32
31
 
33
- # Returns whether running in Synchronous mode
34
- def self.synchronous?
35
- @@synchronous
32
+ # Returns whether minions are enabled to run in their own threads
33
+ def self.enabled?
34
+ @@enabled
36
35
  end
37
36
 
38
37
  # The list of classes for which the current scope must be copied into the
@@ -66,14 +65,14 @@ module ParallelMinion
66
65
  # - :timeout does not affect what happens to the Minion running the
67
66
  # the task, it only affects how long #result will take to return.
68
67
  # - The Minion will continue to run even after the timeout has been exceeded
69
- # - If :synchronous is true, or ParallelMinion::Minion.synchronous is
70
- # set to true, then :timeout is ignored and assumed to be Minion::INFINITE
68
+ # - If :enabled is false, or ParallelMinion::Minion.enabled is false,
69
+ # then :timeout is ignored and assumed to be Minion::INFINITE
71
70
  # since the code is run in the calling thread when the Minion is created
72
71
  #
73
- # :synchronous [Boolean]
74
- # Whether the Minion should run in the current thread
72
+ # :enabled [Boolean]
73
+ # Whether the minion should run in a separate thread
75
74
  # Not recommended in Production, but is useful for debugging purposes
76
- # Default: false
75
+ # Default: ParallelMinion::Minion.enabled?
77
76
  #
78
77
  # *args
79
78
  # Any number of arguments can be supplied that are passed into the block
@@ -112,20 +111,24 @@ module ParallelMinion
112
111
 
113
112
  options = self.class.extract_options!(args).dup
114
113
 
115
- @timeout = (options.delete(:timeout) || Minion::INFINITE).to_f
114
+ @timeout = (options.delete(:timeout) || Minion::INFINITE).to_f
116
115
  @description = (options.delete(:description) || 'Minion').to_s
117
116
  @log_exception = options.delete(:log_exception)
118
- @synchronous = options.delete(:synchronous) || self.class.synchronous?
117
+ @enabled = options.delete(:enabled)
118
+ @enabled = self.class.enabled? if @enabled.nil?
119
119
 
120
120
  # Warn about any unknown options.
121
- options.each_pair { |key,val| logger.warn "Ignoring unknown option: #{key.inspect} => #{val.inspect}" }
121
+ options.each_pair do |key,val|
122
+ logger.warn "Ignoring unknown option: #{key.inspect} => #{val.inspect}"
123
+ warn "ParallelMinion::Minion Ignoring unknown option: #{key.inspect} => #{val.inspect}"
124
+ end
122
125
 
123
126
  # Run the supplied block of code in the current thread for testing or
124
127
  # debugging purposes
125
- if @synchronous == true
128
+ if @enabled == false
126
129
  begin
127
- logger.info("Started synchronously #{@description}")
128
- logger.benchmark_info("Completed synchronously #{@description}", log_exception: @log_exception) do
130
+ logger.info("Started in the current thread: #{@description}")
131
+ logger.benchmark_info("Completed in the current thread: #{@description}", log_exception: @log_exception) do
129
132
  @result = instance_exec(*args, &block)
130
133
  end
131
134
  rescue Exception => exc
@@ -189,12 +192,12 @@ module ParallelMinion
189
192
 
190
193
  # Returns [Boolean] whether the minion is still working on the assigned task
191
194
  def working?
192
- synchronous? ? false : @thread.alive?
195
+ enabled? ? @thread.alive? : false
193
196
  end
194
197
 
195
198
  # Returns [Boolean] whether the minion has completed working on the task
196
199
  def completed?
197
- synchronous? ? true : @thread.stop?
200
+ enabled? ? @thread.stop? : true
198
201
  end
199
202
 
200
203
  # Returns [Boolean] whether the minion failed while performing the assigned task
@@ -211,9 +214,9 @@ module ParallelMinion
211
214
  duration <= 0 ? 0 : duration
212
215
  end
213
216
 
214
- # Returns [Boolean] whether synchronous mode has been enabled for this minion instance
215
- def synchronous?
216
- @synchronous
217
+ # Returns [Boolean] whether this minion is enabled to run in a separate thread
218
+ def enabled?
219
+ @enabled
217
220
  end
218
221
 
219
222
  # Returns the current scopes for each of the models for which scopes will be
@@ -225,7 +228,7 @@ module ParallelMinion
225
228
 
226
229
  protected
227
230
 
228
- @@synchronous = false
231
+ @@enabled = true
229
232
  @@scoped_classes = []
230
233
 
231
234
  # Extract options from a hash.
@@ -9,7 +9,7 @@ module ParallelMinion #:nodoc:
9
9
  # Rails::Application.configure do
10
10
  #
11
11
  # # Run Minions in the current thread to make debugging easier
12
- # config.parallel_minion.synchronous = true
12
+ # config.parallel_minion.enabled = false
13
13
  #
14
14
  # # Add a model so that its current scope is copied to the Minion
15
15
  # config.parallel_minion.scoped_classes << MyScopedModel
@@ -1,3 +1,3 @@
1
1
  module ParallelMinion #:nodoc
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -34,8 +34,8 @@ end
34
34
  class MinionScopeTest < Test::Unit::TestCase
35
35
 
36
36
  context ParallelMinion::Minion do
37
- [false, true].each do |synchronous|
38
- context ".new with synchronous: #{synchronous.inspect}" do
37
+ [false, true].each do |enabled|
38
+ context ".new with enabled: #{enabled.inspect}" do
39
39
  setup do
40
40
  Person.create(name: 'Jack', state: 'FL', zip_code: 38729)
41
41
  Person.create(name: 'John', state: 'FL', zip_code: 35363)
@@ -45,7 +45,7 @@ class MinionScopeTest < Test::Unit::TestCase
45
45
  Person.create(name: 'James', state: 'CA', zip_code: 123123)
46
46
  # Instruct Minions to adhere to any dynamic scopes for Person model
47
47
  ParallelMinion::Minion.scoped_classes << Person
48
- ParallelMinion::Minion.synchronous = synchronous
48
+ ParallelMinion::Minion.enabled = enabled
49
49
  end
50
50
 
51
51
  teardown do
data/test/minion_test.rb CHANGED
@@ -16,10 +16,10 @@ class MinionTest < Test::Unit::TestCase
16
16
 
17
17
  context ParallelMinion::Minion do
18
18
 
19
- [false, true].each do |synchronous|
20
- context ".new with synchronous: #{synchronous.inspect}" do
19
+ [false, true].each do |enabled|
20
+ context ".new with enabled: #{enabled.inspect}" do
21
21
  setup do
22
- ParallelMinion::Minion.synchronous = synchronous
22
+ ParallelMinion::Minion.enabled = enabled
23
23
  end
24
24
 
25
25
  should 'without parameters' do
@@ -96,8 +96,8 @@ class MinionTest < Test::Unit::TestCase
96
96
 
97
97
  should 'timeout' do
98
98
  minion = ParallelMinion::Minion.new(description: 'Test', timeout: 100) { sleep 1 }
99
- # Only Parallel Minions time-out when they exceed timeout
100
- unless synchronous
99
+ # Only Parallel Minions time-out when they exceed the timeout
100
+ if enabled
101
101
  assert_equal nil, minion.result
102
102
  end
103
103
  end
data/test/test_db.sqlite3 CHANGED
Binary file
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: parallel_minion
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Reid Morrison
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-12-03 00:00:00.000000000 Z
11
+ date: 2013-12-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: semantic_logger