request_store_rails 1.0.3 → 2.0.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
- SHA1:
3
- metadata.gz: 6b370ace6ec755d1dc7fa029ee24f92eb5b9caac
4
- data.tar.gz: 59be0018678daaa9cf65c25305c8170fc41a9055
2
+ SHA256:
3
+ metadata.gz: 7bd1299319b0c1e8167b6d68d55e69d4099439824beeac03f8a9fc0c715ee71b
4
+ data.tar.gz: 7d5a0b52520b5f09405ae262f5eb9c984d8faad49886e343331e76b7b1c88249
5
5
  SHA512:
6
- metadata.gz: ff35f1f352936ce0858d15ec30b4e996a7e70e7d62a31137c0303000d1c374a1efa3e02ac6b03f4a7b9822297a693fc96c799ec002167ad32648a3383519349a
7
- data.tar.gz: 188fda858dd967a796197b6989e16ef88878eafe72d69dd61282b02cca96487168ea3fc7dc4824f89453261f3e7518ad46f9870c5b92f1d901b6100d1a4bd338
6
+ metadata.gz: 1a8fd3b6848bf8b92a74610e1803349388b93cbd64f1454c5df608483fb2283022db0210c4cf7d8c797059dd3aebdd038eedad4214672a6c4eabda6c19bb019d
7
+ data.tar.gz: 1ff7ff9d67e0d00447a904e2e3b80b130fca8a24b92759f6d2fd0d4cdcc8878fb28d958e58e7dd9eb1272faa1e5f7e2f47c99ff9d2d8f6c13446528256f4218b
data/README.md CHANGED
@@ -77,11 +77,11 @@ use RequestStoreRails::Middleware
77
77
  ```
78
78
 
79
79
  ## Multi-Threading
80
- The middleware in the gem sets a thread-local variable `:request_id` in
80
+ The middleware in the gem sets a thread-local variable `:request_store_id` in
81
81
  `Thread.current` for the main thread that is executing the request.
82
82
 
83
83
  If you need to spawn threads within a server that is already using thread-based
84
- concurrency, all you need to do is to make sure that the `:request_id`
84
+ concurrency, all you need to do is to make sure that the `:request_store_id`
85
85
  variable is set for your threads, and you will be able to access the
86
86
  `RequestLocals` as usual.
87
87
 
@@ -93,9 +93,9 @@ class ThreadWithContext
93
93
 
94
94
  # Public: Returns a new Thread that preserves the context of the current request.
95
95
  def ThreadWithContext.new(*args)
96
- request_id = Thread.current[:request_id]
96
+ store_id = RequestLocals.current_store_id
97
97
  Thread.new {
98
- Thread.current[:request_id] = request_id
98
+ RequestLocals.set_current_store_id(store_id)
99
99
  yield *args
100
100
  }
101
101
  end
@@ -133,6 +133,35 @@ if RequestStore != RequestLocals
133
133
  end
134
134
  ```
135
135
 
136
+ ## Usage in Sidekiq
137
+ If your code depends on these global variables, it's likely that you'll need
138
+ to avoid collisions in Sidekiq workers (which would happen if the current store
139
+ id is `nil`).
140
+
141
+ You can use the following middleware, using the job id to identify the store:
142
+
143
+ ```ruby
144
+ class Sidekiq::Middleware::Server::RequestStoreRails
145
+ def call(_worker, job, _queue)
146
+ RequestLocals.set_current_store_id(job['jid'])
147
+ yield
148
+ ensure
149
+ RequestLocals.clear!
150
+ RequestLocals.set_current_store_id(nil)
151
+ end
152
+ end
153
+ ```
154
+
155
+ Make sure to configure it as server middleware:
156
+
157
+ ```ruby
158
+ Sidekiq.configure_server do |config|
159
+ config.server_middleware do |chain|
160
+ chain.add Sidekiq::Middleware::Server::RequestStoreRails
161
+ end
162
+ end
163
+ ```
164
+
136
165
  ## Special Thanks
137
166
  The inspiration for this gem, tests, and a big part of the readme were borrowed
138
167
  from the really cool [`request_store`](https://github.com/steveklabnik/request_store) gem.
@@ -5,8 +5,8 @@ require 'concurrent'
5
5
  # Public: Provides per-request global storage, by offering an interface that is
6
6
  # very similar to Rails.cache, or Hash.
7
7
  #
8
- # The store may be shared between threads, as long as the :request_id
9
- # thread-local variable is set.
8
+ # The store may be shared between threads, as long as the current store id is
9
+ # set as a thread-local variable.
10
10
  #
11
11
  # Intended to work in collaboration with the RequestStoreRails middleware, that
12
12
  # will clear the request local variables after each request.
@@ -14,11 +14,15 @@ class RequestLocals
14
14
  include Singleton
15
15
  extend Forwardable
16
16
 
17
+ # Internal: The key of the thread-local variable the library uses to store the
18
+ # identifier of the current store, used during the request lifecycle.
19
+ REQUEST_STORE_ID = :request_store_id
20
+
17
21
  class << self
18
22
  extend Forwardable
19
23
 
20
24
  # Public: Public methods of RequestLocals, they are delegated to the Singleton instance.
21
- def_delegators :instance, :clear!, :clear_all!, :[], :[]=, :fetch, :delete, :exist?, :key?, :empty?
25
+ def_delegators :instance, :clear!, :clear_all!, :current_store_id, :[], :[]=, :fetch, :delete, :exist?, :key?, :empty?
22
26
 
23
27
  # Public: There is no accounting for taste, RequestLocals[:foo] vs RequestLocals.store[:foo]
24
28
  alias_method :store, :instance
@@ -46,7 +50,7 @@ class RequestLocals
46
50
  #
47
51
  # Returns nothing.
48
52
  def clear!
49
- @cache.delete(current_request_id)
53
+ @cache.delete(current_store_id)
50
54
  end
51
55
 
52
56
  # Public: Clears all the request-local variable stores.
@@ -75,6 +79,19 @@ class RequestLocals
75
79
  store.compute_if_absent(key, &block)
76
80
  end
77
81
 
82
+ # Public: The current request is inferred from the current thread.
83
+ #
84
+ # NOTE: It's very important to set the current store id when spawning new
85
+ # threads within a single request, using `RequestLocals.set_current_store_id`.
86
+ def current_store_id
87
+ Thread.current[REQUEST_STORE_ID]
88
+ end
89
+
90
+ # Public: Changes the store RequestLocals will read from in the current thread.
91
+ def self.set_current_store_id(id)
92
+ Thread.current[REQUEST_STORE_ID] = id
93
+ end
94
+
78
95
  protected
79
96
 
80
97
  # Internal: Returns the structure that holds the request-local variables for
@@ -82,14 +99,7 @@ protected
82
99
  #
83
100
  # Returns a ThreadSafe::Cache.
84
101
  def store
85
- @cache.compute_if_absent(current_request_id) { new_store }
86
- end
87
-
88
- # Internal: The current request is inferred from the current thread. It's very
89
- # important to pass on the :request_id thread local variable when spawning new
90
- # threads within a single request.
91
- def current_request_id
92
- Thread.current[:request_id]
102
+ @cache.compute_if_absent(current_store_id) { new_store }
93
103
  end
94
104
 
95
105
  # Internal: Returns a new empty structure where the request-local variables
@@ -2,29 +2,33 @@ require 'securerandom'
2
2
 
3
3
  module RequestStoreRails
4
4
 
5
- # Public: Middleware that takes care of setting the thread-local variable
6
- # :request_id, which enables RequestLocals to associate threads and requests.
5
+ # Public: Middleware that takes care of setting a thread-local variable, which
6
+ # enables RequestLocals to associate threads with the store for a request.
7
7
  class Middleware
8
8
 
9
9
  def initialize(app)
10
10
  @app = app
11
11
  end
12
12
 
13
- # Internal: Assigns the :request_id thread-local variable, and cleans up all
14
- # the request-local variables after the request.
13
+ # Internal: Assigns a thread-local variable to identify the current store,
14
+ # and cleans up all the variables stored for the request once it finishes.
15
15
  def call(env)
16
- Thread.current[:request_id] = extract_request_id(env)
16
+ RequestLocals.set_current_store_id(extract_request_id(env))
17
17
  @app.call(env)
18
18
  ensure
19
19
  RequestLocals.clear!
20
- Thread.current[:request_id] = nil
20
+ RequestLocals.set_current_store_id(nil)
21
21
  end
22
22
 
23
23
  protected
24
24
 
25
25
  # Internal: Extracts the request id from the environment, or generates one.
26
+ #
27
+ # NOTE: We always generate an id to prevent accidental conflicts from an
28
+ # externally provided one, but subclasses of this middleware might override
29
+ # it.
26
30
  def extract_request_id(env)
27
- env['action_dispatch.request_id'] || env['HTTP_X_REQUEST_ID'] || SecureRandom.hex(16)
31
+ SecureRandom.uuid
28
32
  end
29
33
  end
30
34
  end
@@ -1,4 +1,4 @@
1
1
  module RequestStoreRails
2
2
 
3
- VERSION = '1.0.3'
3
+ VERSION = '2.0.0'
4
4
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: request_store_rails
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.3
4
+ version: 2.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Máximo Mussini
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-06-06 00:00:00.000000000 Z
11
+ date: 2019-05-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -86,8 +86,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
86
86
  - !ruby/object:Gem::Version
87
87
  version: '0'
88
88
  requirements: []
89
- rubyforge_project:
90
- rubygems_version: 2.6.11
89
+ rubygems_version: 3.0.3
91
90
  signing_key:
92
91
  specification_version: 4
93
92
  summary: Per-request global storage for Rails