bg 0.0.4 → 0.0.5

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: 5b59fee4ea49e20b0f003c82d4e88cfe8944ba00
4
- data.tar.gz: 5e1d394c114e456a75d342f566777a79f855cf49
3
+ metadata.gz: 4324480197c976cb308ccd3ea1793b5620e01be2
4
+ data.tar.gz: 76fafd8fa06023ebb0beea60f5d9a264293e3647
5
5
  SHA512:
6
- metadata.gz: 0f98b49309738b49b5a2e91d361d7a1a4a7edde4547edade187374461d3be98d4c870820e4488ed57ae5e75b268cc673926b2a18cff7b7d43da41be3db645677
7
- data.tar.gz: e19f24f3030ca8f696859d0b051ca5225095044b978ea68bea7d1cff8e55a834c485393507e509684d354de6b3b130028eb3ef5b8398fb113cf7335ab3712470
6
+ metadata.gz: 02a6086051a13bc6a062fe1490664b4eaf1e5a94f238020423e531038cce1894a2203936bc0fc7f0a8166bc188d25038a3c57f45fbbc16be1fd3fa5c8f78cd54
7
+ data.tar.gz: 49a95bf68e2c28513012074449c522a3803ccf2d02087ec2993f68f7e0d84e4ef2d458326f89902b5cedc18c0a3322044e64feca9de6660433e1aaa9636dd62a
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- bg (0.0.4)
4
+ bg (0.0.5)
5
5
  activejob (>= 5.0)
6
6
  activerecord (>= 5.0)
7
7
  concurrent-ruby (>= 1.0)
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- [![Lines of Code](http://img.shields.io/badge/lines_of_code-121-brightgreen.svg?style=flat)](http://blog.codinghorror.com/the-best-code-is-no-code-at-all/)
1
+ [![Lines of Code](http://img.shields.io/badge/lines_of_code-117-brightgreen.svg?style=flat)](http://blog.codinghorror.com/the-best-code-is-no-code-at-all/)
2
2
  [![Code Status](http://img.shields.io/codeclimate/github/hopsoft/bg.svg?style=flat)](https://codeclimate.com/github/hopsoft/bg)
3
3
  [![Dependency Status](http://img.shields.io/gemnasium/hopsoft/bg.svg?style=flat)](https://gemnasium.com/hopsoft/bg)
4
4
  [![Build Status](http://img.shields.io/travis/hopsoft/bg.svg?style=flat)](https://travis-ci.org/hopsoft/bg)
@@ -30,19 +30,25 @@ end
30
30
 
31
31
  ```ruby
32
32
  user = User.find(params[:id])
33
- user.do_hard_work # blocking in-process
34
- user.async.do_hard_work # non-blocking in-process
35
- user.defer.do_hard_work # non-blocking out-of-process background job
33
+
34
+ # blocking in-process
35
+ user.do_hard_work
36
+
37
+ # non-blocking in-process separate thread
38
+ user.async.do_hard_work
39
+
40
+ # non-blocking out-of-process background job
41
+ user.defer.do_hard_work
36
42
  user.defer(queue: :low, wait: 5.minutes).do_hard_work
37
43
  ```
38
44
 
39
- ## Provisos
45
+ ## Deferrable
40
46
 
41
- Bg leverages [GlobalID::Identification](https://github.com/rails/globalid) to marshal ActiveRecord instances across thread & process boundaries.
42
- This means that state is not shared between the main process/thread with the process/thread actually executing the method.
47
+ `Bg::Deferrable` leverages [GlobalID::Identification](https://github.com/rails/globalid) to marshal ActiveRecord instances across process boundaries.
48
+ This means that state is not shared between the main process & the process actually executing the method.
43
49
 
44
- * __Do not__ depend on lexically scoped bindings when invoking methods with `Bg::Deferrable`.
45
- * __Do not__ pass unmarshallable types as arguments with `Bg::Deferrable`.
50
+ * __Do not__ depend on lexically scoped bindings when invoking methods.
51
+ * __Do not__ pass unmarshallable types as arguments.
46
52
  `Bg::Deferrable` will prepare arguments for enqueuing, but best practice is to follow
47
53
  Sidekiq's [simple parameters](https://github.com/mperham/sidekiq/wiki/Best-Practices#1-make-your-job-parameters-small-and-simple) rule.
48
54
 
@@ -52,9 +58,6 @@ This means that state is not shared between the main process/thread with the pro
52
58
 
53
59
  ```ruby
54
60
  user = User.find(params[:id])
55
- user.update(name: "new value") # persisted changes will be available in Bg invoked methods
56
-
57
- user.async.do_hard_work 1, true, "foo", :bar, Time.now
58
61
  user.defer.do_hard_work 1, true, "foo"
59
62
  ```
60
63
 
@@ -62,15 +65,41 @@ user.defer.do_hard_work 1, true, "foo"
62
65
 
63
66
  ```ruby
64
67
  user = User.find(params[:id])
65
- user.name = "new value" # in memory changes will not be available in Bg invoked methods
68
+ # in memory changes will not be available in Bg::Deferrable invoked methods
69
+ user.name = "new value"
66
70
 
67
- user.async.do_hard_work do
71
+ # args may not marshal properly
72
+ user.defer.do_hard_work :foo, Time.now, instance_of_complex_type
73
+
74
+ user.defer.do_hard_work do
68
75
  # blocks are not supported
69
76
  end
77
+ ```
70
78
 
71
- user.defer.do_hard_work :foo, Time.now # args won't marshal properly
79
+ ## Asyncable
72
80
 
73
- user.defer.do_hard_work do
81
+ `Bg::Asyncable` disallows invoking methods that take blocks as an argument.
82
+
83
+ * __Important:__ It's your responsibility to protect shared data between threads
84
+
85
+ ### Examples
86
+
87
+ #### Good
88
+
89
+ ```ruby
90
+ user = User.find(params[:id])
91
+ user.name = "new value"
92
+ user.async.do_hard_work 1, true, "foo"
93
+ user.async.do_hard_work :foo, Time.now, instance_of_complex_type
94
+ ```
95
+
96
+ #### Bad
97
+
98
+ ```ruby
99
+ user = User.find(params[:id])
100
+
101
+ user.async.do_hard_work do
74
102
  # blocks are not supported
75
103
  end
76
104
  ```
105
+
@@ -1,51 +1,47 @@
1
1
  require "active_record"
2
2
  require "concurrent"
3
- require "globalid"
4
3
 
5
4
  module Bg
6
5
  class Asyncable
7
6
  class Wrapper
8
7
  include ::Concurrent::Async
9
- attr_reader :global_id, :delay
10
8
 
11
- def initialize(global_id, delay: 0)
9
+ def initialize(object, wait: 0)
12
10
  # IMPORTANT: call super without any arguments
13
11
  # https://ruby-concurrency.github.io/concurrent-ruby/Concurrent/Async.html
14
12
  super()
15
- @global_id = global_id
16
- @delay = delay.to_f
13
+ @object = object
14
+ @wait = wait.to_f
17
15
  end
18
16
 
19
17
  def invoke_method(name, *args)
20
- sleep delay if delay > 0
21
- ::ActiveRecord::Base.connection_pool.with_connection do
22
- global_id.find.send name, *args
18
+ sleep @wait if @wait > 0
19
+ base = self.is_a?(::ActiveRecord::Base) ? self.class : ::ActiveRecord::Base
20
+ base.connection_pool.with_connection do
21
+ @object.send name, *args
23
22
  end
24
23
  end
25
24
  end
26
25
 
27
26
  module Behavior
28
- def async(delay: 0)
29
- ::Bg::Asyncable.new(self, delay: delay.to_f)
27
+ def async(wait: 0)
28
+ ::Bg::Asyncable.new(self, wait: wait.to_f)
30
29
  end
31
30
  end
32
31
 
33
- attr_reader :object, :delay
34
-
35
- def initialize(object, delay: 0)
36
- raise ::ArgumentError unless object.is_a?(::GlobalID::Identification)
32
+ def initialize(object, wait: 0)
37
33
  @object = object
38
- @delay = delay.to_f
34
+ @wait = wait.to_f
39
35
  end
40
36
 
41
37
  def method_missing(name, *args)
42
- if object.respond_to? name
38
+ if @object.respond_to? name
43
39
  raise ::ArgumentError.new("blocks are not supported") if block_given?
44
40
  begin
45
- wrapped = ::Bg::Asyncable::Wrapper.new(object.to_global_id, delay: delay)
41
+ wrapped = ::Bg::Asyncable::Wrapper.new(@object, wait: @wait)
46
42
  wrapped.async.invoke_method name, *args
47
43
  rescue ::StandardError => e
48
- raise ::ArgumentError.new("Failed to execute method asynchronously! <#{object.class.name}##{name}> #{e.message}")
44
+ raise ::ArgumentError.new("Failed to execute method asynchronously! <#{@object.class.name}##{name}> #{e.message}")
49
45
  ensure
50
46
  return
51
47
  end
@@ -54,7 +50,7 @@ module Bg
54
50
  end
55
51
 
56
52
  def respond_to?(name)
57
- return true if object.respond_to? name
53
+ return true if @object.respond_to? name
58
54
  super
59
55
  end
60
56
  end
@@ -27,8 +27,6 @@ module Bg
27
27
  end
28
28
  end
29
29
 
30
- attr_reader :object, :queue, :wait
31
-
32
30
  def initialize(object, queue: :default, wait: 0)
33
31
  raise ::ArgumentError unless object.is_a?(::GlobalID::Identification)
34
32
  @object = object
@@ -37,14 +35,14 @@ module Bg
37
35
  end
38
36
 
39
37
  def method_missing(name, *args)
40
- if object.respond_to? name
38
+ if @object.respond_to? name
41
39
  raise ::ArgumentError.new("blocks are not supported") if block_given?
42
40
  begin
43
- queue_args = { queue: queue }
44
- queue_args[:wait] = wait if wait > 0
45
- job = ::Bg::DeferredMethodCallJob.set(**queue_args).perform_later object, name.to_s, *self.class.make_enqueable(args)
41
+ queue_args = { queue: @queue }
42
+ queue_args[:wait] = @wait if @wait > 0
43
+ job = ::Bg::DeferredMethodCallJob.set(**queue_args).perform_later @object, name.to_s, *self.class.make_enqueable(args)
46
44
  rescue ::StandardError => e
47
- raise ::ArgumentError.new("Failed to background method call! <#{object.class.name}##{name}> #{e.message}")
45
+ raise ::ArgumentError.new("Failed to background method call! <#{@object.class.name}##{name}> #{e.message}")
48
46
  ensure
49
47
  return job
50
48
  end
@@ -53,7 +51,7 @@ module Bg
53
51
  end
54
52
 
55
53
  def respond_to?(name)
56
- return true if object.respond_to? name
54
+ return true if @object.respond_to? name
57
55
  super
58
56
  end
59
57
  end
@@ -1,3 +1,3 @@
1
1
  module Bg
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
@@ -36,4 +36,9 @@ class Bg::DeferredMethodCallJobTest < ::ActiveJob::TestCase
36
36
  end
37
37
  end
38
38
 
39
+ test "#perform_now properly invokes the method" do
40
+ obj = ::Bg::BackgroundableObject.new(:example)
41
+ assert ::Bg::DeferredMethodCallJob.perform_now(obj, :update)
42
+ end
43
+
39
44
  end
@@ -4,9 +4,9 @@ require_relative "../lib/bg"
4
4
  require_relative "backgroundable_object"
5
5
  require "minitest/autorun"
6
6
  require "purdytest"
7
- #require "pry"
8
- #require "pry-nav"
9
- #require "pry-stack_explorer"
7
+ require "pry"
8
+ require "pry-nav"
9
+ require "pry-stack_explorer"
10
10
 
11
11
  ::ActiveSupport::TestCase.test_order = :random
12
12
  ::GlobalID.app = "test"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bg
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nathan Hopkins