request_store_rails 2.0.0 → 3.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 +4 -4
- data/README.md +18 -44
- data/lib/request_locals.rb +24 -9
- data/lib/request_store_rails/middleware.rb +3 -3
- data/lib/request_store_rails/version.rb +1 -1
- metadata +18 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: f8fce44e58aadca2344b59aa90defca178623e6d9c85d112d93bf565dfd5201c
|
|
4
|
+
data.tar.gz: d02fb9bd71f920fcad84e3a21be15c4d2c2333e517bc84b8158c398d80a0e11e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: dcd870787ebc47f6e5db5b3e20052e793dc2b2930435d2b159b8e1e9d6737a2cfbe765691f27986cbb5656c40ecd79b7a72ede46753f4dc8e2d1a886daf97612
|
|
7
|
+
data.tar.gz: d5c90ad7949b83d53b1fa3b36fe2e59e80c65488d2be2ec341ad44d74e4b12885995971a7824806d37c4ad16c1278481de32f42ab860cbc9e1aa06cbd241099d
|
data/README.md
CHANGED
|
@@ -1,28 +1,17 @@
|
|
|
1
1
|
RequestLocals
|
|
2
2
|
=====================
|
|
3
|
-
[](
|
|
4
|
-
[](http://inch-ci.org/github/ElMassimo/request_store_rails)
|
|
3
|
+
[](https://badge.fury.io/rb/request_store_rails)
|
|
4
|
+
[](https://github.com/ElMassimo/request_store_rails/actions/workflows/ci.yml)
|
|
5
|
+
[](https://qlty.sh/gh/ElMassimo/projects/request_store_rails)
|
|
6
|
+
[](https://qlty.sh/gh/ElMassimo/projects/request_store_rails)
|
|
8
7
|
[](https://github.com/ElMassimo/request_store_rails/blob/master/LICENSE.txt)
|
|
9
8
|
|
|
10
9
|
If you have ever needed to use a global variable in Rails, you know it sucks.
|
|
11
10
|
|
|
12
|
-
One
|
|
13
|
-
|
|
11
|
+
One common solution is the awesome
|
|
12
|
+
[`request_store`](https://github.com/steveklabnik/request_store):
|
|
14
13
|
|
|
15
14
|
```ruby
|
|
16
|
-
# Using Thread.current
|
|
17
|
-
def self.foo
|
|
18
|
-
Thread.current[:foo] ||= 0
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
def self.foo=(value)
|
|
22
|
-
Thread.current[:foo] = value
|
|
23
|
-
end
|
|
24
|
-
|
|
25
|
-
# Using RequestStore
|
|
26
15
|
def self.foo
|
|
27
16
|
RequestStore.fetch(:foo) { 0 }
|
|
28
17
|
end
|
|
@@ -34,13 +23,8 @@ end
|
|
|
34
23
|
|
|
35
24
|
### The problem
|
|
36
25
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
- Using `request_store`, the storage is _*not actually*_ request local. Variables
|
|
41
|
-
are stored in `Thread.current`, except that the storage is cleared after each
|
|
42
|
-
request. However, this does not work when you need to use multiple threads per
|
|
43
|
-
request, _different_ threads access _different_ stores.
|
|
26
|
+
`request_store` scopes values to the execution context handling the request.
|
|
27
|
+
When work moves to another thread, that thread accesses a different store.
|
|
44
28
|
|
|
45
29
|
### The solution
|
|
46
30
|
|
|
@@ -62,28 +46,18 @@ def self.foo=(value)
|
|
|
62
46
|
end
|
|
63
47
|
```
|
|
64
48
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
in a true _request-local_ way.
|
|
68
|
-
|
|
69
|
-
### No Rails? No Problem!
|
|
70
|
-
|
|
71
|
-
A Railtie is added that configures the Middleware for you, but if you're not
|
|
72
|
-
using Rails, no biggie! Just use the Middleware yourself, however you need.
|
|
73
|
-
You'll probably have to shove this somewhere:
|
|
74
|
-
|
|
75
|
-
```ruby
|
|
76
|
-
use RequestStoreRails::Middleware
|
|
77
|
-
```
|
|
49
|
+
Everywhere you used `RequestStore.store`, change it to `RequestLocals.store`.
|
|
50
|
+
Now your variables will actually be stored in a true _request-local_ way.
|
|
78
51
|
|
|
79
52
|
## Multi-Threading
|
|
80
|
-
The middleware
|
|
81
|
-
`
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
`RequestLocals`
|
|
53
|
+
The middleware stores each request's context in
|
|
54
|
+
`ActiveSupport::IsolatedExecutionState`, the same mechanism used by Rails'
|
|
55
|
+
`CurrentAttributes`. Existing `RequestLocals` usage automatically follows the
|
|
56
|
+
thread or fiber isolation level configured by Rails, without application changes.
|
|
57
|
+
|
|
58
|
+
When explicitly spawning a new thread, propagate the current store id with
|
|
59
|
+
`RequestLocals.set_current_store_id` so the new thread can access the same
|
|
60
|
+
request-local values.
|
|
87
61
|
|
|
88
62
|
A good way to apply this pattern is by encapsulating it into a helper class:
|
|
89
63
|
|
data/lib/request_locals.rb
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
require 'singleton'
|
|
2
2
|
require 'forwardable'
|
|
3
3
|
require 'concurrent'
|
|
4
|
+
require 'active_support/isolated_execution_state'
|
|
4
5
|
|
|
5
6
|
# Public: Provides per-request global storage, by offering an interface that is
|
|
6
7
|
# very similar to Rails.cache, or Hash.
|
|
7
8
|
#
|
|
8
|
-
# The store may be shared between
|
|
9
|
-
#
|
|
9
|
+
# The store may be shared between execution contexts by propagating the current
|
|
10
|
+
# store id with `RequestLocals.set_current_store_id`.
|
|
10
11
|
#
|
|
11
12
|
# Intended to work in collaboration with the RequestStoreRails middleware, that
|
|
12
13
|
# will clear the request local variables after each request.
|
|
@@ -14,9 +15,11 @@ class RequestLocals
|
|
|
14
15
|
include Singleton
|
|
15
16
|
extend Forwardable
|
|
16
17
|
|
|
17
|
-
# Internal: The key
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
# Internal: The execution-state key used for the request identifier.
|
|
19
|
+
REQUEST_STORE_ID = :request_store_rails_store_id
|
|
20
|
+
|
|
21
|
+
# Internal: The execution-state backend used for the request identifier.
|
|
22
|
+
CONTEXT = ActiveSupport::IsolatedExecutionState
|
|
20
23
|
|
|
21
24
|
class << self
|
|
22
25
|
extend Forwardable
|
|
@@ -79,17 +82,25 @@ class RequestLocals
|
|
|
79
82
|
store.compute_if_absent(key, &block)
|
|
80
83
|
end
|
|
81
84
|
|
|
82
|
-
# Public: The current request is inferred from the current
|
|
85
|
+
# Public: The current request is inferred from the current execution context.
|
|
83
86
|
#
|
|
84
87
|
# NOTE: It's very important to set the current store id when spawning new
|
|
85
88
|
# threads within a single request, using `RequestLocals.set_current_store_id`.
|
|
86
89
|
def current_store_id
|
|
87
|
-
|
|
90
|
+
context[REQUEST_STORE_ID]
|
|
88
91
|
end
|
|
89
92
|
|
|
90
|
-
# Public: Changes the store RequestLocals will read from in the current
|
|
93
|
+
# Public: Changes the store RequestLocals will read from in the current execution context.
|
|
91
94
|
def self.set_current_store_id(id)
|
|
92
|
-
|
|
95
|
+
if id.nil?
|
|
96
|
+
context.delete(REQUEST_STORE_ID)
|
|
97
|
+
else
|
|
98
|
+
context[REQUEST_STORE_ID] = id
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
def self.context
|
|
103
|
+
CONTEXT
|
|
93
104
|
end
|
|
94
105
|
|
|
95
106
|
protected
|
|
@@ -102,6 +113,10 @@ protected
|
|
|
102
113
|
@cache.compute_if_absent(current_store_id) { new_store }
|
|
103
114
|
end
|
|
104
115
|
|
|
116
|
+
def context
|
|
117
|
+
self.class.context
|
|
118
|
+
end
|
|
119
|
+
|
|
105
120
|
# Internal: Returns a new empty structure where the request-local variables
|
|
106
121
|
# will be stored.
|
|
107
122
|
def new_store
|
|
@@ -2,15 +2,15 @@ require 'securerandom'
|
|
|
2
2
|
|
|
3
3
|
module RequestStoreRails
|
|
4
4
|
|
|
5
|
-
# Public: Middleware that
|
|
6
|
-
#
|
|
5
|
+
# Public: Middleware that sets the isolated execution context, which enables
|
|
6
|
+
# RequestLocals to associate concurrent execution 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
|
|
13
|
+
# Internal: Assigns the execution context that identifies the current store,
|
|
14
14
|
# and cleans up all the variables stored for the request once it finishes.
|
|
15
15
|
def call(env)
|
|
16
16
|
RequestLocals.set_current_store_id(extract_request_id(env))
|
metadata
CHANGED
|
@@ -1,14 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: request_store_rails
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 3.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Máximo Mussini
|
|
8
|
-
autorequire:
|
|
9
8
|
bindir: bin
|
|
10
9
|
cert_chain: []
|
|
11
|
-
date:
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
12
11
|
dependencies:
|
|
13
12
|
- !ruby/object:Gem::Dependency
|
|
14
13
|
name: rake
|
|
@@ -52,6 +51,20 @@ dependencies:
|
|
|
52
51
|
- - "~>"
|
|
53
52
|
- !ruby/object:Gem::Version
|
|
54
53
|
version: '1.0'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: activesupport
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '7.0'
|
|
61
|
+
type: :runtime
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '7.0'
|
|
55
68
|
description: RequestLocals gives you per-request global storage in Rails
|
|
56
69
|
email:
|
|
57
70
|
- maximomussini@gmail.com
|
|
@@ -70,7 +83,6 @@ homepage: https://github.com/ElMassimo/request_store_rails
|
|
|
70
83
|
licenses:
|
|
71
84
|
- MIT
|
|
72
85
|
metadata: {}
|
|
73
|
-
post_install_message:
|
|
74
86
|
rdoc_options:
|
|
75
87
|
- "--charset=UTF-8"
|
|
76
88
|
require_paths:
|
|
@@ -79,15 +91,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
79
91
|
requirements:
|
|
80
92
|
- - ">="
|
|
81
93
|
- !ruby/object:Gem::Version
|
|
82
|
-
version:
|
|
94
|
+
version: '2.7'
|
|
83
95
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
84
96
|
requirements:
|
|
85
97
|
- - ">="
|
|
86
98
|
- !ruby/object:Gem::Version
|
|
87
99
|
version: '0'
|
|
88
100
|
requirements: []
|
|
89
|
-
rubygems_version:
|
|
90
|
-
signing_key:
|
|
101
|
+
rubygems_version: 4.0.20
|
|
91
102
|
specification_version: 4
|
|
92
103
|
summary: Per-request global storage for Rails
|
|
93
104
|
test_files: []
|