inst-jobs 1.0.1 → 1.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 +4 -4
- data/lib/delayed/message_sending.rb +36 -27
- data/lib/delayed/performable_method.rb +18 -8
- data/lib/delayed/version.rb +1 -1
- data/spec/delayed/message_sending_spec.rb +53 -3
- data/spec/shared/delayed_method.rb +2 -2
- data/spec/spec_helper.rb +9 -0
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6d65c567b52e2baf26955d266c9fededc001deab65d871e6e60a42a905d552e8
|
4
|
+
data.tar.gz: b4d487088aba583188c90650a42a20726f84230e346c321b4b94ddc5c25fe36e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9ade674610c5a1a4a04e4a6078b45c38358e7c7af79a417d5e6941d968e1565bc5e217405ad1ca427b373ee0d89bdbc28772f8ed52047394e8760fc09a79b60a
|
7
|
+
data.tar.gz: 216706e128397e84ba87d495e4b09d30eb58f35ab4821e8ef6f484d5f6226a959cab04a8bfdfa22916f19dad53e7ee01bbe1128bd61fb402aad29885ac81839f
|
@@ -7,32 +7,45 @@ end
|
|
7
7
|
module Delayed
|
8
8
|
module MessageSending
|
9
9
|
class DelayProxy < BasicObject
|
10
|
-
def initialize(object, synchronous: false,
|
10
|
+
def initialize(object, synchronous: false, sender: nil, **enqueue_args)
|
11
11
|
@object = object
|
12
12
|
@enqueue_args = enqueue_args
|
13
13
|
@synchronous = synchronous
|
14
|
-
@
|
14
|
+
@sender = sender
|
15
15
|
end
|
16
16
|
|
17
17
|
def method_missing(method, *args, **kwargs)
|
18
|
+
# method doesn't exist? must be method_missing; assume private access
|
19
|
+
@sender = nil if !@sender.nil? &&
|
20
|
+
!@object.methods.include?(method) &&
|
21
|
+
!@object.protected_methods.include?(method) &&
|
22
|
+
!@object.private_methods.include?(method)
|
23
|
+
|
24
|
+
sender_is_object = @sender == @object
|
25
|
+
sender_is_class = @sender.is_a?(@object.class)
|
26
|
+
|
27
|
+
# even if the call is async, if the call is _going_ to generate an error, we make it synchronous
|
28
|
+
# so that the error is generated immediately, instead of waiting for it to fail in a job,
|
29
|
+
# which might go unnoticed
|
30
|
+
if !@sender.nil? && !@synchronous
|
31
|
+
@synchronous = true if !sender_is_object && @object.private_methods.include?(method)
|
32
|
+
@synchronous = true if !sender_is_class && @object.protected_methods.include?(method)
|
33
|
+
end
|
34
|
+
|
18
35
|
if @synchronous
|
19
|
-
if @
|
20
|
-
if kwargs.empty?
|
21
|
-
return @object.public_send(method, *args)
|
22
|
-
else
|
23
|
-
return @object.public_send(method, *args, **kwargs)
|
24
|
-
end
|
25
|
-
else
|
36
|
+
if @sender.nil? || sender_is_object || sender_is_class && @object.protected_methods.include?(method)
|
26
37
|
if kwargs.empty?
|
27
38
|
return @object.send(method, *args)
|
28
39
|
else
|
29
40
|
return @object.send(method, *args, **kwargs)
|
30
41
|
end
|
31
42
|
end
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
43
|
+
|
44
|
+
if kwargs.empty?
|
45
|
+
return @object.public_send(method, *args)
|
46
|
+
else
|
47
|
+
return @object.public_send(method, *args, **kwargs)
|
48
|
+
end
|
36
49
|
end
|
37
50
|
|
38
51
|
ignore_transaction = @enqueue_args.delete(:ignore_transaction)
|
@@ -50,7 +63,8 @@ module Delayed
|
|
50
63
|
::Delayed::Job.enqueue(::Delayed::PerformableMethod.new(@object, method,
|
51
64
|
args: args, kwargs: kwargs,
|
52
65
|
on_failure: on_failure,
|
53
|
-
on_permanent_failure: on_permanent_failure
|
66
|
+
on_permanent_failure: on_permanent_failure,
|
67
|
+
sender: @sender),
|
54
68
|
**@enqueue_args)
|
55
69
|
end
|
56
70
|
return nil
|
@@ -61,14 +75,15 @@ module Delayed
|
|
61
75
|
args: args,
|
62
76
|
kwargs: kwargs,
|
63
77
|
on_failure: on_failure,
|
64
|
-
on_permanent_failure: on_permanent_failure
|
78
|
+
on_permanent_failure: on_permanent_failure,
|
79
|
+
sender: @sender),
|
65
80
|
**@enqueue_args)
|
66
81
|
result = nil unless ignore_transaction
|
67
82
|
result
|
68
83
|
end
|
69
84
|
end
|
70
85
|
|
71
|
-
def delay(
|
86
|
+
def delay(sender: nil, **enqueue_args)
|
72
87
|
# support procs/methods as enqueue arguments
|
73
88
|
enqueue_args.each do |k,v|
|
74
89
|
if v.respond_to?(:call)
|
@@ -76,21 +91,15 @@ module Delayed
|
|
76
91
|
end
|
77
92
|
end
|
78
93
|
|
79
|
-
|
94
|
+
sender ||= __calculate_sender_for_delay
|
80
95
|
|
81
|
-
DelayProxy.new(self,
|
96
|
+
DelayProxy.new(self, sender: sender, **enqueue_args)
|
82
97
|
end
|
83
98
|
|
84
|
-
def
|
99
|
+
def __calculate_sender_for_delay
|
85
100
|
# enforce public send in dev and test, but not prod (since it uses
|
86
101
|
# debug APIs, it's expensive)
|
87
|
-
|
88
|
-
sender = self.sender(1)
|
89
|
-
# if the caller isn't self, use public_send; i.e. enforce method visibility
|
90
|
-
sender != self
|
91
|
-
else
|
92
|
-
false
|
93
|
-
end
|
102
|
+
return sender(1) if ::Rails.env.test? || ::Rails.env.development?
|
94
103
|
end
|
95
104
|
|
96
105
|
module ClassMethods
|
@@ -114,7 +123,7 @@ module Delayed
|
|
114
123
|
if synchronous
|
115
124
|
super(*args, **kwargs)
|
116
125
|
else
|
117
|
-
delay(**enqueue_args).method_missing(method_name, *args, synchronous: true, **kwargs)
|
126
|
+
delay(sender: __calculate_sender_for_delay, **enqueue_args).method_missing(method_name, *args, synchronous: true, **kwargs)
|
118
127
|
end
|
119
128
|
end)
|
120
129
|
end
|
@@ -1,8 +1,8 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Delayed
|
4
|
-
class PerformableMethod < Struct.new(:object, :method, :args, :kwargs, :fail_cb, :permanent_fail_cb, :
|
5
|
-
def initialize(object, method, args: [], kwargs: {}, on_failure: nil, on_permanent_failure: nil,
|
4
|
+
class PerformableMethod < Struct.new(:object, :method, :args, :kwargs, :fail_cb, :permanent_fail_cb, :sender)
|
5
|
+
def initialize(object, method, args: [], kwargs: {}, on_failure: nil, on_permanent_failure: nil, sender: nil)
|
6
6
|
raise NoMethodError, "undefined method `#{method}' for #{object.inspect}" unless object.respond_to?(method, true)
|
7
7
|
|
8
8
|
self.object = object
|
@@ -11,7 +11,13 @@ module Delayed
|
|
11
11
|
self.method = method.to_sym
|
12
12
|
self.fail_cb = on_failure
|
13
13
|
self.permanent_fail_cb = on_permanent_failure
|
14
|
-
self.
|
14
|
+
self.sender = sender
|
15
|
+
begin
|
16
|
+
YAML.dump(sender)
|
17
|
+
rescue
|
18
|
+
# if for some reason you can't dump the sender, just drop it
|
19
|
+
self.sender = nil
|
20
|
+
end
|
15
21
|
end
|
16
22
|
|
17
23
|
def display_name
|
@@ -25,17 +31,21 @@ module Delayed
|
|
25
31
|
|
26
32
|
def perform
|
27
33
|
kwargs = self.kwargs || {}
|
28
|
-
|
34
|
+
|
35
|
+
sender_is_object = sender == object
|
36
|
+
sender_is_class = sender.is_a?(object.class)
|
37
|
+
|
38
|
+
if sender.nil? || sender_is_object || sender_is_class && object.protected_methods.include?(method)
|
29
39
|
if kwargs.empty?
|
30
|
-
object.
|
40
|
+
object.send(method, *args)
|
31
41
|
else
|
32
|
-
object.
|
42
|
+
object.send(method, *args, **kwargs)
|
33
43
|
end
|
34
44
|
else
|
35
45
|
if kwargs.empty?
|
36
|
-
object.
|
46
|
+
object.public_send(method, *args)
|
37
47
|
else
|
38
|
-
object.
|
48
|
+
object.public_send(method, *args, **kwargs)
|
39
49
|
end
|
40
50
|
end
|
41
51
|
end
|
data/lib/delayed/version.rb
CHANGED
@@ -8,21 +8,38 @@ RSpec.describe Delayed::MessageSending do
|
|
8
8
|
allow(::Rails.env).to receive(:test?).and_return(true)
|
9
9
|
end
|
10
10
|
|
11
|
-
|
12
|
-
|
11
|
+
before (:all) do
|
12
|
+
class SpecClass
|
13
13
|
def call_private(**enqueue_args)
|
14
14
|
delay(**enqueue_args).private_method
|
15
15
|
end
|
16
16
|
|
17
|
+
def call_protected(**enqueue_args)
|
18
|
+
other = self.class.new
|
19
|
+
other.delay(**enqueue_args).protected_method
|
20
|
+
end
|
21
|
+
|
17
22
|
private
|
18
23
|
|
19
24
|
def private_method
|
20
25
|
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
def protected_method
|
30
|
+
end
|
21
31
|
end
|
22
32
|
end
|
23
33
|
|
34
|
+
after(:all) do
|
35
|
+
Object.send(:remove_const, :SpecClass)
|
36
|
+
end
|
37
|
+
|
38
|
+
let(:klass) { SpecClass }
|
39
|
+
|
24
40
|
it "allows an object to send a private message to itself" do
|
25
|
-
klass.new.call_private
|
41
|
+
job = klass.new.call_private(ignore_transaction: true)
|
42
|
+
job.invoke_job
|
26
43
|
end
|
27
44
|
|
28
45
|
it "allows an object to send a private message to itself synchronouosly" do
|
@@ -48,4 +65,37 @@ RSpec.describe Delayed::MessageSending do
|
|
48
65
|
allow(::Rails.env).to receive(:development?).and_return(false)
|
49
66
|
klass.new.delay(synchronous: true).private_method
|
50
67
|
end
|
68
|
+
|
69
|
+
it "allows an object to send a protected message to itself" do
|
70
|
+
job = klass.new.call_protected(ignore_transaction: true)
|
71
|
+
job.invoke_job
|
72
|
+
end
|
73
|
+
|
74
|
+
it "allows an object to send a protected message to itself synchronouosly" do
|
75
|
+
klass.new.call_protected(synchronous: true)
|
76
|
+
end
|
77
|
+
|
78
|
+
it "warns about directly sending a protected message asynchronously" do
|
79
|
+
expect { klass.new.delay.protected_method }.to raise_error(NoMethodError)
|
80
|
+
end
|
81
|
+
|
82
|
+
it "warns about directly sending a protected message synchronusly" do
|
83
|
+
expect { klass.new.delay(synchronous: true).protected_method }.to raise_error(NoMethodError)
|
84
|
+
end
|
85
|
+
|
86
|
+
it "doesn't explode if you can't dump the sender" do
|
87
|
+
klass = Class.new do
|
88
|
+
def delay_something
|
89
|
+
Kernel.delay.sleep(1)
|
90
|
+
end
|
91
|
+
|
92
|
+
def encode_with(encoder)
|
93
|
+
raise "yaml encoding failed"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
obj = klass.new
|
98
|
+
expect { YAML.dump(obj) }.to raise_error("yaml encoding failed")
|
99
|
+
expect { obj.delay_something }.not_to raise_error
|
100
|
+
end
|
51
101
|
end
|
@@ -82,11 +82,11 @@ shared_examples_for 'random ruby objects' do
|
|
82
82
|
obj = klass.new
|
83
83
|
method = double()
|
84
84
|
|
85
|
-
expect(Delayed::PerformableMethod).to receive(:new).with(obj, :test_method, args: [1,2,3], kwargs: {synchronous: true}, on_failure: nil, on_permanent_failure: nil).and_return(method)
|
85
|
+
expect(Delayed::PerformableMethod).to receive(:new).with(obj, :test_method, args: [1,2,3], kwargs: {synchronous: true}, on_failure: nil, on_permanent_failure: nil, sender: obj).and_return(method)
|
86
86
|
expect(Delayed::Job).to receive(:enqueue).with(method, :enqueue_arg_1 => :thing)
|
87
87
|
obj.test_method(1,2,3)
|
88
88
|
|
89
|
-
expect(Delayed::PerformableMethod).to receive(:new).with(obj, :test_method, args: [4], kwargs: {:synchronous=>true}, on_failure: nil, on_permanent_failure: nil).and_return(method)
|
89
|
+
expect(Delayed::PerformableMethod).to receive(:new).with(obj, :test_method, args: [4], kwargs: {:synchronous=>true}, on_failure: nil, on_permanent_failure: nil, sender: obj).and_return(method)
|
90
90
|
expect(Delayed::Job).to receive(:enqueue).with(method, :enqueue_arg_1 => :thing)
|
91
91
|
obj.test_method(4)
|
92
92
|
|
data/spec/spec_helper.rb
CHANGED
@@ -35,6 +35,15 @@ RSpec.configure do |config|
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
+
module NoYamlDump
|
39
|
+
def encode_with(coder)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
# example groups are often the sender, and if we try to serialize them,
|
43
|
+
# the resultant object is then encoded in the sender, and then we serialize
|
44
|
+
# again, and it just keeps getting bigger and bigger and bigger...
|
45
|
+
RSpec::Core::ExampleGroup.include(NoYamlDump)
|
46
|
+
|
38
47
|
ENV['TEST_ENV_NUMBER'] ||= '1'
|
39
48
|
ENV['TEST_DB_HOST'] ||= 'localhost'
|
40
49
|
ENV['TEST_DB_DATABASE'] ||= "inst-jobs-test-#{ENV['TEST_ENV_NUMBER']}"
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: inst-jobs
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tobias Luetke
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: exe
|
11
11
|
cert_chain: []
|
12
|
-
date: 2020-10-
|
12
|
+
date: 2020-10-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|