gb_dispatch 0.0.1 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2d9b3773249dedae96894b9cc9addb02ca59c1e2
4
- data.tar.gz: c3ee56270eb83c3cf0e68dc0568e450fd718c8c6
3
+ metadata.gz: b286c03ff9e3e0a61a04f57de98ffa2fe7ac351b
4
+ data.tar.gz: 12018509b5949974b22228aa45da2f510842e20d
5
5
  SHA512:
6
- metadata.gz: cf2c44fe50c484e501bd7d89deb51ee47c0349bae1ec9c76f55329600336ea9cddfc5d10456b7ef78a591b7a8e7781465ab9524857ca0c827bf1978ad440a894
7
- data.tar.gz: 796181ec676e815b3c57266d58d6224f9fd20d5033c86b7b1b83f7d8c65c55a370f8bb556418ca68de48ea105c4f081be910bda220a6e203d29ed2f43ad507e2
6
+ metadata.gz: a28e7e5c7fb3e48ebd91b7ee6403eabc298843187b9df271971a9d099a55cc4e21152de0df1a490b30d0466542dab7dd417cdf3c9c728011959ae20688d4d792
7
+ data.tar.gz: 326a1b1f2c0a14c8f82c6348deea13db1881a58a39bfa1174acda2426a465a245ac49c95bd52d983d8d653a18b1c418bd8c7646193a60d276695925983f0313f
data/.gitignore CHANGED
@@ -11,4 +11,5 @@
11
11
  *.so
12
12
  *.o
13
13
  *.a
14
- mkmf.log
14
+ *.gem
15
+ mkmf.log
data/.idea/modules.xml CHANGED
@@ -2,6 +2,7 @@
2
2
  <project version="4">
3
3
  <component name="ProjectModuleManager">
4
4
  <modules>
5
+ <module fileurl="file://$PROJECT_DIR$/.idea/gb-dispatch.iml" filepath="$PROJECT_DIR$/.idea/gb-dispatch.iml" />
5
6
  <module fileurl="file://$PROJECT_DIR$/.idea/gb_dispatch.iml" filepath="$PROJECT_DIR$/.idea/gb_dispatch.iml" />
6
7
  </modules>
7
8
  </component>
data/Gemfile CHANGED
@@ -3,7 +3,7 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in gb_dispatch.gemspec
4
4
  gemspec
5
5
 
6
- gem 'celluloid', '~>0.15.2'
6
+ gem 'celluloid', '<=0.15.2'
7
7
  group :test do
8
8
  gem 'rspec'
9
9
  gem 'simplecov', :require => false
data/Gemfile.lock CHANGED
@@ -1,8 +1,8 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- gb_dispatch (0.0.1)
5
- celluloid (~> 0.15.2)
4
+ gb_dispatch (0.0.2)
5
+ celluloid (>= 0.15.2)
6
6
 
7
7
  GEM
8
8
  remote: https://rubygems.org/
@@ -12,7 +12,7 @@ GEM
12
12
  diff-lcs (1.2.5)
13
13
  docile (1.1.5)
14
14
  json (1.8.3)
15
- rake (10.3.2)
15
+ rake (10.5.0)
16
16
  rspec (3.4.0)
17
17
  rspec-core (~> 3.4.0)
18
18
  rspec-expectations (~> 3.4.0)
@@ -26,7 +26,7 @@ GEM
26
26
  diff-lcs (>= 1.2.0, < 2.0)
27
27
  rspec-support (~> 3.4.0)
28
28
  rspec-support (3.4.1)
29
- simplecov (0.10.0)
29
+ simplecov (0.11.1)
30
30
  docile (~> 1.1.0)
31
31
  json (~> 1.8)
32
32
  simplecov-html (~> 0.10.0)
@@ -38,8 +38,11 @@ PLATFORMS
38
38
 
39
39
  DEPENDENCIES
40
40
  bundler (~> 1.6)
41
- celluloid (~> 0.15.2)
41
+ celluloid (<= 0.15.2)
42
42
  gb_dispatch!
43
43
  rake (~> 10.0)
44
44
  rspec
45
45
  simplecov
46
+
47
+ BUNDLED WITH
48
+ 1.11.2
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
- # GbDispatch
1
+ # GBDispatch
2
2
 
3
- Library allows easy to dispatch block of code for queues.
3
+ Library allows to easily dispatch block of code for queues.
4
+ It is inspired by Grand Central Dispatch behaviour.
4
5
 
5
6
  ## Installation
6
7
 
@@ -18,12 +19,18 @@ Or install it yourself as:
18
19
 
19
20
  $ gem install gb_dispatch
20
21
 
22
+ Then in your script
23
+
24
+ ```ruby
25
+ require 'gb_dispatch'
26
+ ```
27
+
21
28
  ## Usage
22
29
 
23
30
  To dispatch asynchronously
24
31
 
25
32
  ```ruby
26
- GBDispatch.dispatch_async_on_queue :my_queue do
33
+ GBDispatch.dispatch_async :my_queue do
27
34
  puts 'my code here'
28
35
  end
29
36
  ```
@@ -31,14 +38,51 @@ end
31
38
  for synchronous execution
32
39
 
33
40
  ```ruby
34
- GBDispatch.dispatch_sync_on_queue :my_queue do
41
+ my_result = GBDispatch.dispatch_sync :my_queue do
42
+ puts 'my code here'
43
+ end
44
+ ```
45
+
46
+ for delay execution
47
+
48
+ ```ruby
49
+ delay = 4.5 #seconds
50
+ GBDispatch.dispatch_after delay, :my_queue do
35
51
  puts 'my code here'
36
52
  end
37
53
  ```
38
54
 
55
+ ### Using with Rails
56
+
57
+ If you are using Rails, all blocks are wrapped in connection pool,
58
+ so you don't need to worry about creating and removing new connections.
59
+ Only thing you need to do, is to increase connection pool size
60
+ by number of cores of your machine.
61
+
62
+ ## How it works
63
+
64
+ ### Queues
65
+
66
+ For each created queue there is a new thread created. However this threads
67
+ are used only for scheduling purpose. All code execution happens on execution pool.
68
+
69
+ Queues ensure order of execution, but they don't guarantee that all blocks from one queue
70
+ will be executed on the same thread.
71
+
72
+ ### Execution pool
73
+
74
+ This is pool of thread where your code will be executed.
75
+ Amount of threads in the pool match the amount of cores of your machine
76
+ (except if you have only one core, there will be 2 threads).
77
+
78
+ ### Exceptions
79
+
80
+ GBDispatch is designed in the way, that if there is exception thrown it will not crash the whole app/script.
81
+ All exceptions will be logged. If you use +#dispatch_sync+ method, thrown exception will be returned as a result of your block.
82
+
39
83
  ## Contributing
40
84
 
41
- 1. Fork it ( https://github.com/[my-github-username]/gb_dispatch/fork )
85
+ 1. Fork it ( https://github.com/GenieBelt/gb_dispatch/fork )
42
86
  2. Create your feature branch (`git checkout -b my-new-feature`)
43
87
  3. Commit your changes (`git commit -am 'Add some feature'`)
44
88
  4. Push to the branch (`git push origin my-new-feature`)
data/Rakefile CHANGED
@@ -11,7 +11,7 @@ task :build => :spec do
11
11
  sh 'gem build ./gb_dispatch.gemspec'
12
12
  end
13
13
 
14
- task :release do
14
+ task :release_local do
15
15
  require './lib/gb_dispatch/version'
16
16
  sh "gem push gb_dispatch-#{GBDispatch::VERSION}.gem --host http://tools.bobisdead.com/gems"
17
17
  end
data/gb_dispatch.gemspec CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ['Kacper Kawecki']
10
10
  spec.email = ['kacper@geniebelt.com']
11
11
  spec.summary = %q{GCD emulation for ruby}
12
- spec.description = %q{Allows to dispatch block of code for queues}
12
+ spec.description = %q{Grand central dispatch emulation for ruby. It allows to easily run asynchronous code. }
13
13
  spec.homepage = 'https://github.com/GenieBelt/gb-dispatch'
14
14
  spec.license = 'MIT'
15
15
 
@@ -18,7 +18,8 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ['lib']
20
20
 
21
- spec.add_dependency 'celluloid', '~> 0.15.2'
21
+ spec.add_dependency 'celluloid', '>= 0.15.2'
22
22
  spec.add_development_dependency 'bundler', '~> 1.6'
23
23
  spec.add_development_dependency 'rake', '~> 10.0'
24
+ spec.add_development_dependency 'rspec', '~> 3.4.0'
24
25
  end
@@ -16,5 +16,4 @@ class CentralDispatch
16
16
  end
17
17
  end
18
18
  end
19
-
20
19
  end
@@ -1,12 +1,22 @@
1
1
  require 'singleton'
2
2
  require 'gb_dispatch/runner'
3
3
  require 'gb_dispatch/queue'
4
+ # Queue manager for simulating Grand Central Dispatch behaviour.
5
+ #
6
+ # It is singleton class, so all calls should be invoked through +GBDispatch::Manager.instance+
4
7
  module GBDispatch
5
8
  class Manager
6
9
  include Singleton
7
10
 
11
+ # Returns queue of given name.
12
+ #
13
+ # If queue doesn't exists it will create you a new one.
14
+ # Remember that for each allocated queue, there is new thread allocated.
15
+ # @param name [String, Symbol] if not passed, default queue will be returned.
16
+ # @return [GBDispatch::Queue]
8
17
  def get_queue(name=:default)
9
- queue = Celluloid::Actor[name.to_sym]
18
+ name = name.to_sym
19
+ queue = Celluloid::Actor[name]
10
20
  unless queue
11
21
  supervisor = Queue.supervise_as name, name, @pool
12
22
  queue = supervisor.actors.first
@@ -14,19 +24,64 @@ module GBDispatch
14
24
  queue
15
25
  end
16
26
 
17
- # @param queue [GBDispatch::Queue]
27
+ # Run asynchronously given block of code on given queue.
28
+ #
29
+ # This is a proxy for {GBDispatch::Queue#perform} method.
30
+ # @param queue [GBDispatch::Queue] queue on which block will be executed
31
+ # @return [nil]
32
+ # @example
33
+ # my_queue = GBDispatch::Manager.instance.get_queue :my_queue
34
+ # GBDispatch::Manager.instance.run_async_on_queue my_queue do
35
+ # #my delayed code here - probably slow one :)
36
+ # puts 'Delayed Hello World!'
37
+ # end
18
38
  def run_async_on_queue(queue)
19
39
  queue.async.perform ->() { yield }
20
40
  end
21
41
 
22
- # @param queue [GBDispatch::Queue]
42
+ # Run given block of code on given queue and wait for result.
43
+ #
44
+ # This method use {GBDispatch::Queue#perform} and wait for result.
45
+ # @param queue [GBDispatch::Queue] queue on which block will be executed
46
+ # @example sets +my_result+ to 42
47
+ # my_queue = GBDispatch::Manager.instance.get_queue :my_queue
48
+ # my_result = GBDispatch::Manager.instance.run_sync_on_queue my_queue do
49
+ # # my complicated code here
50
+ # puts 'Delayed Hello World!'
51
+ # # return value
52
+ # 42
53
+ # end
23
54
  def run_sync_on_queue(queue)
24
55
  future = queue.future.perform ->() { yield }
25
56
  future.value
26
57
  end
27
58
 
59
+ # Run given block of code on given queue with delay.
60
+ # @param time [Fixnum, Float] delay in seconds
61
+ # @param queue [GBDispatch::Queue] queue on which block will be executed
62
+ # @return [nil]
63
+ # @example Will print 'Hello word!' after 5 seconds.
64
+ # my_queue = GBDispatch::Manager.instance.get_queue :my_queue
65
+ # my_result = GBDispatch::Manager.instance.run_after_on_queue 5, my_queue do
66
+ # puts 'Hello World!'
67
+ # end
68
+ #
69
+ def run_after_on_queue(time, queue)
70
+ queue.perform_after time, ->(){ yield }
71
+ end
72
+
73
+
74
+ # :nodoc:
75
+ def exit
76
+ @pool.terminate
77
+ Celluloid::Actor.all.each do |actor|
78
+ actor.terminate if actor.alive?
79
+ end
80
+ end
81
+
28
82
  private
29
83
 
84
+ # :nodoc:
30
85
  def initialize
31
86
  @pool = Runner.pool
32
87
  end
@@ -13,9 +13,12 @@ module GBDispatch
13
13
  @thread_pool = thread_pool
14
14
  end
15
15
 
16
+ # Perform given block
16
17
  #
18
+ # If used with rails it will wrap block with connection pool.
17
19
  # @param block [Proc]
18
20
  # @yield if there is no block given it yield without param.
21
+ # @return [Object, Exception] returns value of executed block or exception if block execution failed.
19
22
  def perform(block=nil)
20
23
  Thread.current[:name] ||= name
21
24
  if defined?(Rails) && defined?(ActiveRecord::Base)
@@ -39,5 +42,16 @@ module GBDispatch
39
42
  end
40
43
  end
41
44
  end
45
+
46
+ # Perform block after given period
47
+ # @param time [Fixnum]
48
+ # @param block [Proc]
49
+ # @yield if there is no block given it yield without param.
50
+ def perform_after(time, block=nil)
51
+ after(time) do
52
+ block = ->(){ yield } unless block
53
+ self.async.perform block
54
+ end
55
+ end
42
56
  end
43
57
  end
@@ -1,3 +1,3 @@
1
1
  module GBDispatch
2
- VERSION = "0.0.1"
2
+ VERSION = '0.0.2'
3
3
  end
data/lib/gb_dispatch.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  require 'gb_dispatch/version'
2
2
  require 'gb_dispatch/manager'
3
+ require 'celluloid'
3
4
 
4
5
  # Library to dispatch block on queues.
5
6
  # It is inspired by GCD but implementation is based on Celluloid.
@@ -12,36 +13,59 @@ require 'gb_dispatch/manager'
12
13
  # of the machine.
13
14
  #
14
15
  module GBDispatch
16
+ # Get queue of given name
17
+ # @return [GBDispatch:Queue]
18
+ # @param name [#to_sym]
19
+ def self.get_queue(name)
20
+ GBDispatch::Manager.instance.get_queue(name)
21
+ end
22
+
15
23
  # Dispatch asynchronously on queue
16
24
  # @param queue [Symbol, GBDispatch::Queue] queue object or name
17
25
  # @yield block to execute
18
- def self.dispatch_async_on_queue(queue)
26
+ def self.dispatch_async(queue)
19
27
  queue = GBDispatch::Manager.instance.get_queue(queue) unless queue.is_a? GBDispatch::Queue
20
28
  GBDispatch::Manager.instance.run_async_on_queue queue do
21
29
  yield
22
30
  end
23
31
  end
24
32
 
25
- # Get queue of given name
26
- # @return [GBDispatch:Queue]
27
- # @param name [#to_sym]
28
- def self.get_queue(name)
29
- GBDispatch::Manager.instance.get_queue(name)
33
+ # Dispatch synchronously on queue and return result
34
+ # @param queue [Symbol, GBDispatch::Queue] queue object or name
35
+ # @yield block to execute
36
+ def self.dispatch_sync(queue)
37
+ queue = GBDispatch::Manager.instance.get_queue(queue) unless queue.is_a? GBDispatch::Queue
38
+ GBDispatch::Manager.instance.run_sync_on_queue queue do
39
+ yield
40
+ end
30
41
  end
31
42
 
32
- # Dispatch synchronously on queue and return result
43
+
44
+ # Dispatch on queue with delay.
45
+ # @param delay [Fixnum, Float] delay in seconds
33
46
  # @param queue [Symbol, GBDispatch::Queue] queue object or name
34
47
  # @yield block to execute
35
- def self.dispatch_sync_on_queue(queue)
48
+ def self.dispatch_after(delay, queue)
36
49
  queue = GBDispatch::Manager.instance.get_queue(queue) unless queue.is_a? GBDispatch::Queue
37
50
  GBDispatch::Manager.instance.run_async_on_queue queue do
38
51
  yield
39
52
  end
40
53
  end
41
54
 
55
+
42
56
  # Setup logger. By default it use Celluloid logger
43
57
  # @param logger [Logger]
44
58
  def self.logger=(logger)
45
59
  Celluloid.logger = logger
46
60
  end
61
+
62
+ class << self
63
+ alias_method :dispatch_sync_on_queue, :dispatch_sync
64
+ alias_method :dispatch_async_on_queue, :dispatch_async
65
+ alias_method :dispatch_after_on_queue, :dispatch_after
66
+ end
67
+
68
+ at_exit do
69
+ GBDispatch::Manager.instance.exit
70
+ end
47
71
  end
@@ -0,0 +1,85 @@
1
+ require 'spec_helper'
2
+ require 'gb_dispatch'
3
+
4
+ describe GBDispatch do
5
+
6
+ it 'should run dispatch_async' do
7
+ a = []
8
+ GBDispatch.dispatch_async :test do
9
+ sleep(0.01)
10
+ a << 1
11
+ end
12
+ GBDispatch.dispatch_async :test do
13
+ a << 2
14
+ end
15
+ expect(a.empty?).to be_truthy
16
+ sleep(0.02)
17
+ expect(a).to eq [1, 2]
18
+ end
19
+
20
+ it 'should run dispatch_async_on_queue' do
21
+ a = []
22
+ GBDispatch.dispatch_async_on_queue :test do
23
+ sleep(0.01)
24
+ a << 1
25
+ end
26
+ GBDispatch.dispatch_async_on_queue :test do
27
+ a << 2
28
+ end
29
+ expect(a.empty?).to be_truthy
30
+ sleep(0.02)
31
+ expect(a).to eq [1, 2]
32
+ end
33
+
34
+ it 'should run dispatch_sync' do
35
+ a = []
36
+ GBDispatch.dispatch_async :test do
37
+ sleep(0.02)
38
+ a << 1
39
+ end
40
+ result = GBDispatch.dispatch_sync :test do
41
+ a << 2
42
+ a
43
+ end
44
+ expect(result).to eq [1,2]
45
+ end
46
+
47
+ it 'should run dispatch_sync_on_queue' do
48
+ a = []
49
+ GBDispatch.dispatch_async :test do
50
+ sleep(0.02)
51
+ a << 1
52
+ end
53
+ result = GBDispatch.dispatch_sync_on_queue :test do
54
+ a << 2
55
+ a
56
+ end
57
+ expect(result).to eq [1,2]
58
+ end
59
+
60
+ it 'should run dispatch_after' do
61
+ a = []
62
+ GBDispatch.dispatch_after 0.1, :test do
63
+ a << 1
64
+ end
65
+ expect(a.empty?).to be_truthy
66
+ sleep(0.15)
67
+ expect(a).to eq [1]
68
+ end
69
+
70
+ it 'should run dispatch_after_on_queue' do
71
+ a = []
72
+ GBDispatch.dispatch_after_on_queue 0.1, :test do
73
+ a << 1
74
+ end
75
+ expect(a.empty?).to be_truthy
76
+ sleep(0.15)
77
+ expect(a).to eq [1]
78
+ end
79
+
80
+ it 'should return proper queue' do
81
+ queue = GBDispatch.get_queue :test
82
+ expect(queue.name).to eq :test
83
+ expect(queue).to be_a GBDispatch::Queue
84
+ end
85
+ end
data/spec/queue_spec.rb CHANGED
@@ -55,7 +55,7 @@ describe GBDispatch::Queue do
55
55
  queue.async.perform ->() do
56
56
  (11..20).each { |x| a << x }
57
57
  end
58
- sleep(0.06)
58
+ sleep(0.08)
59
59
  expect(a).to eq (0..20).to_a
60
60
  queue.terminate
61
61
  end
@@ -75,6 +75,22 @@ describe GBDispatch::Queue do
75
75
  end
76
76
  end
77
77
 
78
+ context 'after' do
79
+ it 'should bea bale to run block of code after specified time' do
80
+ a = []
81
+ queue = GBDispatch::Queue.new(:test, @pool)
82
+ queue.perform_after 0.5, ->() { a << rand() }
83
+ queue.perform_after 0.7, ->() { a << rand() }
84
+ sleep 0.4
85
+ expect(a.count).to eq 0
86
+ sleep 0.2
87
+ expect(a.count).to eq 1
88
+ sleep 0.2
89
+ expect(a.count).to eq 2
90
+ queue.terminate
91
+ end
92
+ end
93
+
78
94
  context 'rails' do
79
95
  before(:each) do
80
96
  class Rails
metadata CHANGED
@@ -1,27 +1,27 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: gb_dispatch
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kacper Kawecki
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-01-12 00:00:00.000000000 Z
11
+ date: 2016-01-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: celluloid
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: 0.15.2
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: 0.15.2
27
27
  - !ruby/object:Gem::Dependency
@@ -52,7 +52,22 @@ dependencies:
52
52
  - - "~>"
53
53
  - !ruby/object:Gem::Version
54
54
  version: '10.0'
55
- description: Allows to dispatch block of code for queues
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 3.4.0
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 3.4.0
69
+ description: 'Grand central dispatch emulation for ruby. It allows to easily run asynchronous
70
+ code. '
56
71
  email:
57
72
  - kacper@geniebelt.com
58
73
  executables: []
@@ -78,6 +93,7 @@ files:
78
93
  - lib/gb_dispatch/queue.rb
79
94
  - lib/gb_dispatch/runner.rb
80
95
  - lib/gb_dispatch/version.rb
96
+ - spec/dispatch_spec.rb
81
97
  - spec/queue_spec.rb
82
98
  - spec/runner_spec.rb
83
99
  - spec/spec_helper.rb
@@ -101,11 +117,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
101
117
  version: '0'
102
118
  requirements: []
103
119
  rubyforge_project:
104
- rubygems_version: 2.4.8
120
+ rubygems_version: 2.5.1
105
121
  signing_key:
106
122
  specification_version: 4
107
123
  summary: GCD emulation for ruby
108
124
  test_files:
125
+ - spec/dispatch_spec.rb
109
126
  - spec/queue_spec.rb
110
127
  - spec/runner_spec.rb
111
128
  - spec/spec_helper.rb