concurrent_rails 0.2.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a0352c1516c930c65708383fa734cd7444b02b0a213c0ef1f794e5e31f8e1fdf
4
- data.tar.gz: 33ec089c95b33ff31a4652a073feac356e8b23a8d7e30bd214ea0a0dbc4aedcb
3
+ metadata.gz: f546ccc88f5ebbe088d526b38964a490ccbd7ad2e71a540efd8967c0ff608170
4
+ data.tar.gz: 50cb65d1f7600f44aa900179614c143d5e402e296f80f926eda2233b9c3dc289
5
5
  SHA512:
6
- metadata.gz: a486a3ab777574962127795db050fd2615b69594d0bc88adb5114368c7d90492f2b51b237817f97118a31969396d53171bf66371240577051977a052d935148a
7
- data.tar.gz: db095fe9e33e527a3ade62e8a40aec1866718bfce6b55ef519775cd1761d78b1eb1868d8c8b0ab799dcd05f78980ba16e31f5a7912b87ab3e2dd49d917dab004
6
+ metadata.gz: 0b33613492e179d066fbc5882140693fee391862241b5f76d6cd18d3fafb9c35079c8ba9eefbca11ede757f491fca51c4433ae207dc584d9ac3f39ebe498eabe
7
+ data.tar.gz: '0329ed54f4e87a12910dc345993193feff12537ea8fecf9d57125966696cd314deb86fbe3774c306b7a60d23802e2e8e3ac98ef79e56e2a1062d70f406d4dbba'
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  ![status](https://github.com/luizkowalski/concurrent_rails/actions/workflows/ruby.yml/badge.svg?branch=master)
4
4
 
5
- Multithread is hard. [concurrent-ruby](https://github.com/ruby-concurrency/concurrent-ruby) did an amazing job implementing the concepts of multithread in the Ruby world. The problem is that Rails doesn't play nice with it. Rails have a complex way of managing threads called Executor and concurrent-ruby (most specifically, [Future](https://github.com/ruby-concurrency/concurrent-ruby/blob/master/docs-source/future.md)) does not work seamlessly with it.
5
+ Multithread is hard. [concurrent-ruby](https://github.com/ruby-concurrency/concurrent-ruby) did an amazing job implementing the concepts of multithread in the Ruby world. The problem is that Rails doesn't play nice with it. Rails has a complex way of managing threads called Executor and concurrent-ruby (most specifically, [Future](https://github.com/ruby-concurrency/concurrent-ruby/blob/master/docs-source/future.md)) does not work seamlessly with it.
6
6
 
7
7
  The goal of this gem is to provide a simple library that allows the developer to work with Futures without having to care about Rails's Executor and the whole pack of problems that come with it: autoload, thread pools, active record connections, etc.
8
8
 
@@ -174,12 +174,12 @@ irb(main):007:0> multi.errors
174
174
  It is worth mention that a failed proc will return `nil`.
175
175
 
176
176
  ## Testing
177
- If you are using RSpec, you will notice that it might not play well with threads. ActiveRecord opens a database connection for every thread and since RSpec tests are wrapped in a transaction, by the time you promise tries to access something on the database, for example, a user, gems like Database Cleaner probably already triggered and deleted the user, resulting in `ActiveRecord::RecordNotFound` errors. You have a couple of solutions like disable transactional fixtures if you are using it or update the Database Cleaner strategy (that will result in much slower tests).
178
- Since none of these solutions were satisfactory to me, I created `ConcurrentRails::Testing` with two strategies: `immediate!` and `fake!`. When you wrap a Promise's `future` with `immediate!`, the executor gets replaced from `:io` to `:immediate`. It still returns a promise anyway. This is not the case with `fake!` strategy: it executes the task outside the `ConcurrentRails` engine and returns whatever `.value` would return:
177
+ If you are using RSpec, you will notice that it might not play well with threads. ActiveRecord opens a database connection for every thread and since RSpec tests are wrapped in a transaction, by the time your promise tries to access something on the database, for example, a user, gems like Database Cleaner probably already triggered and deleted the user, resulting in `ActiveRecord::RecordNotFound` errors. You have a couple of solutions like disable transactional fixtures if you are using it or update the Database Cleaner strategy (that will result in much slower tests).
178
+ Since none of these solutions were satisfactory to me, I created `ConcurrentRails::Testing` with two strategies: `immediate` and `fake`. When you wrap a Promise's `future` with `immediate`, the executor gets replaced from `:io` to `:immediate`. It still returns a promise anyway. This is not the case with `fake` strategy: it executes the task outside the `ConcurrentRails` engine and returns whatever `.value` would return:
179
179
 
180
- `immediate!` strategy:
180
+ `immediate` strategy:
181
181
  ```ruby
182
- irb(main):001:1* result = ConcurrentRails::Testing.immediate! do
182
+ irb(main):001:1* result = ConcurrentRails::Testing.immediate do
183
183
  irb(main):002:1* ConcurrentRails::Promises.future { 42 }
184
184
  irb(main):003:0> end
185
185
  =>
@@ -191,10 +191,10 @@ irb(main):005:0> result.executor
191
191
  => :immediate # <-- default executor (:io) gets replaced
192
192
  ```
193
193
 
194
- `fake!` strategy:
194
+ `fake` strategy:
195
195
 
196
196
  ```ruby
197
- irb(main):001:1* result = ConcurrentRails::Testing.fake! do
197
+ irb(main):001:1* result = ConcurrentRails::Testing.fake do
198
198
  irb(main):002:1* ConcurrentRails::Promises.future { 42 }
199
199
  irb(main):003:0> end
200
200
  => 42 # <-- yields the task but does not return a Promise
@@ -202,6 +202,8 @@ irb(main):004:0> result.class
202
202
  => Integer
203
203
  ```
204
204
 
205
+ You can also set the stragegy globally using `ConcurrentRails::Testing.fake!` or `ConcurrentRails::Testing.immediate!`
206
+
205
207
  ## Further reading
206
208
 
207
209
  For more information on how Futures work and how Rails handle multithread check these links:
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module ConcurrentRails::Adapters
4
- module Delay
3
+ module ConcurrentRails
4
+ module DelayAdapter
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  class_methods do
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module ConcurrentRails::Adapters
4
- module Future
3
+ module ConcurrentRails
4
+ module FutureAdapter
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  class_methods do
@@ -1,13 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'concurrent_rails/adapters/future'
4
- require 'concurrent_rails/adapters/delay'
3
+ require 'concurrent_rails/future_adapter'
4
+ require 'concurrent_rails/delay_adapter'
5
5
 
6
6
  module ConcurrentRails
7
7
  class Promises
8
8
  include Concurrent::Promises::FactoryMethods
9
- include ConcurrentRails::Adapters::Delay
10
- include ConcurrentRails::Adapters::Future
9
+ include ConcurrentRails::DelayAdapter
10
+ include ConcurrentRails::FutureAdapter
11
11
 
12
12
  def initialize(executor)
13
13
  @executor = executor
@@ -16,7 +16,7 @@ module ConcurrentRails
16
16
  %i[value value!].each do |method_name|
17
17
  define_method(method_name) do |timeout = nil, timeout_value = nil|
18
18
  permit_concurrent_loads do
19
- instance.__send__(method_name, timeout, timeout_value)
19
+ instance.public_send(method_name, timeout, timeout_value)
20
20
  end
21
21
  end
22
22
  end
@@ -25,7 +25,7 @@ module ConcurrentRails
25
25
  define_method(chainable) do |*args, &task|
26
26
  method = "#{chainable}_on"
27
27
  @instance = rails_wrapped do
28
- instance.__send__(method, executor, *args, &task)
28
+ instance.public_send(method, executor, *args, &task)
29
29
  end
30
30
 
31
31
  self
@@ -5,33 +5,37 @@ module ConcurrentRails
5
5
  class << self
6
6
  attr_reader :execution_mode
7
7
 
8
- %i[immediate fake].each do |exec_method|
9
- define_method("#{exec_method}!") do |&task|
10
- @execution_mode = exec_method
11
- result = task.call
8
+ %w[immediate fake real].each do |test_mode|
9
+ define_method(test_mode) do |&task|
10
+ @execution_mode = test_mode
11
+ result = task.call
12
12
  @execution_mode = :real
13
13
 
14
14
  result
15
15
  end
16
16
 
17
- define_method("#{exec_method}?") do
18
- execution_mode == exec_method
17
+ define_method("#{test_mode}!") do
18
+ @execution_mode = test_mode
19
19
  end
20
- end
21
20
 
22
- module TestingFuture
23
- def future(*args, &task)
24
- if ConcurrentRails::Testing.immediate?
25
- future_on(:immediate, *args, &task)
26
- elsif ConcurrentRails::Testing.fake?
27
- yield
28
- else
29
- super
30
- end
21
+ define_method("#{test_mode}?") do
22
+ execution_mode == test_mode
31
23
  end
32
24
  end
25
+ end
33
26
 
34
- ConcurrentRails::Promises.extend(TestingFuture)
27
+ module TestingFuture
28
+ def future(*args, &task)
29
+ if ConcurrentRails::Testing.immediate?
30
+ future_on(:immediate, *args, &task)
31
+ elsif ConcurrentRails::Testing.fake?
32
+ yield
33
+ else
34
+ super
35
+ end
36
+ end
35
37
  end
38
+
39
+ ConcurrentRails::Promises.extend(TestingFuture)
36
40
  end
37
41
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ConcurrentRails
4
- VERSION = '0.2.1'
4
+ VERSION = '0.4.0'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: concurrent_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Luiz Eduardo Kowalski
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-06-15 00:00:00.000000000 Z
11
+ date: 2022-09-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -24,62 +24,76 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '5.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest-reporters
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.5'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.5'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: rubocop
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
45
  - - ">="
32
46
  - !ruby/object:Gem::Version
33
- version: '1.12'
47
+ version: '1.33'
34
48
  type: :development
35
49
  prerelease: false
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
52
  - - ">="
39
53
  - !ruby/object:Gem::Version
40
- version: '1.12'
54
+ version: '1.33'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rubocop-minitest
43
57
  requirement: !ruby/object:Gem::Requirement
44
58
  requirements:
45
59
  - - ">="
46
60
  - !ruby/object:Gem::Version
47
- version: '0.12'
61
+ version: '0.21'
48
62
  type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
66
  - - ">="
53
67
  - !ruby/object:Gem::Version
54
- version: '0.12'
68
+ version: '0.21'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: rubocop-performance
57
71
  requirement: !ruby/object:Gem::Requirement
58
72
  requirements:
59
73
  - - ">="
60
74
  - !ruby/object:Gem::Version
61
- version: '1.10'
75
+ version: '1.14'
62
76
  type: :development
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
80
  - - ">="
67
81
  - !ruby/object:Gem::Version
68
- version: '1.10'
82
+ version: '1.14'
69
83
  - !ruby/object:Gem::Dependency
70
- name: sqlite3
84
+ name: ruby-lsp
71
85
  requirement: !ruby/object:Gem::Requirement
72
86
  requirements:
73
- - - "~>"
87
+ - - ">="
74
88
  - !ruby/object:Gem::Version
75
- version: '1.4'
89
+ version: '0.3'
76
90
  type: :development
77
91
  prerelease: false
78
92
  version_requirements: !ruby/object:Gem::Requirement
79
93
  requirements:
80
- - - "~>"
94
+ - - ">="
81
95
  - !ruby/object:Gem::Version
82
- version: '1.4'
96
+ version: '0.3'
83
97
  description: Small library to make concurrent-ruby and Rails play nice together
84
98
  email:
85
99
  - luizeduardokowalski@gmail.com
@@ -91,9 +105,9 @@ files:
91
105
  - README.md
92
106
  - Rakefile
93
107
  - lib/concurrent_rails.rb
94
- - lib/concurrent_rails/adapters/delay.rb
95
- - lib/concurrent_rails/adapters/future.rb
108
+ - lib/concurrent_rails/delay_adapter.rb
96
109
  - lib/concurrent_rails/future.rb
110
+ - lib/concurrent_rails/future_adapter.rb
97
111
  - lib/concurrent_rails/multi.rb
98
112
  - lib/concurrent_rails/promises.rb
99
113
  - lib/concurrent_rails/railtie.rb
@@ -103,9 +117,7 @@ homepage: https://github.com/luizkowalski/concurrent_rails
103
117
  licenses:
104
118
  - MIT
105
119
  metadata:
106
- homepage_uri: https://github.com/luizkowalski/concurrent_rails
107
- source_code_uri: https://github.com/luizkowalski/concurrent_rails
108
- changelog_uri: https://github.com/luizkowalski/concurrent_rails/blob/master/CHANGELOG.md
120
+ rubygems_mfa_required: 'true'
109
121
  post_install_message:
110
122
  rdoc_options: []
111
123
  require_paths:
@@ -114,14 +126,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
114
126
  requirements:
115
127
  - - ">="
116
128
  - !ruby/object:Gem::Version
117
- version: '2.6'
129
+ version: '2.7'
118
130
  required_rubygems_version: !ruby/object:Gem::Requirement
119
131
  requirements:
120
132
  - - ">="
121
133
  - !ruby/object:Gem::Version
122
134
  version: '0'
123
135
  requirements: []
124
- rubygems_version: 3.2.20
136
+ rubygems_version: 3.3.22
125
137
  signing_key:
126
138
  specification_version: 4
127
139
  summary: Multithread is hard