fragmentary 0.4.1 → 0.5.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/CHANGELOG.md +10 -0
- data/README.md +8 -2
- data/fragmentary.gemspec +1 -1
- data/lib/fragmentary/config.rb +22 -12
- data/lib/fragmentary/fragment.rb +20 -11
- data/lib/fragmentary/handler.rb +2 -24
- data/lib/fragmentary/jobs/dispatch_handlers_job.rb +1 -3
- data/lib/fragmentary/jobs/send_requests_job.rb +1 -1
- data/lib/fragmentary/publisher.rb +2 -0
- data/lib/fragmentary/request_queue.rb +31 -16
- data/lib/fragmentary/session_user.rb +20 -12
- data/lib/fragmentary/subscriber.rb +20 -7
- data/lib/fragmentary/subscription.rb +7 -5
- data/lib/fragmentary/user_session.rb +3 -1
- data/lib/fragmentary/version.rb +1 -1
- metadata +8 -8
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: e4f080639f4562093503dc31128557031c54fc9b3b8c7dca5502a3146645b6a2
|
|
4
|
+
data.tar.gz: e2a5964a78778703ffc96e57d9b760db87b61d1273643c4d5a85f598f7c6ea74
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 68f38663f547ca5961615e046c4f420d99a1d2d8a04b2b43cd143ceea17a3618787d5a58295bcd133b143aa0e1e23936fe2f91519e7def427edfcfe5b4b7e2c5
|
|
7
|
+
data.tar.gz: 932884c05012d780804cd4f6c50819b5b9f8abf90d0535be50d938291300aa5a5c5f26dea327febb7592c43f9805902670fb6967d98e749a0382709fe89ec959
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
### 0.5.0
|
|
2
|
+
- Update to support Rails 7.x and Ruby 3.x
|
|
3
|
+
- Asynchronous internal application requests enqueued while executing a Fragmentary::Handler are now offloaded to a separate async process to prevent them delaying other processes.
|
|
4
|
+
- When sending asynchronous internal requests, any queue_suffix that is present is included in the request parameters so that if the request spawns secondary requests, they can be run on the same ActiveJob queue (requires appropriate handling of the queue_suffix parameter by the application).
|
|
5
|
+
- Allows queued internal application requests to be removed from queues for an individual application instance.
|
|
6
|
+
- Destroying a fragment now destroys all of its children as well.
|
|
7
|
+
- The session scheme for internal requests is set to 'https' if the host_root_url of the request_queue sending the request requires it.
|
|
8
|
+
- Allows multiple session_users per user_type for internal application requests, each assigned to different user_groups, e.g. multiple 'admin' users, multiple 'signed_in' users etc.
|
|
9
|
+
- Allows RequestQueue.send_all to take additional arguments for delay, queue_suffix, priority and user_group
|
|
10
|
+
|
|
1
11
|
### 0.4.1
|
|
2
12
|
- Fixes a problem with session initialization when sending requests generated by Handler subclasses
|
|
3
13
|
|
data/README.md
CHANGED
|
@@ -18,7 +18,7 @@ In simple cases, Rails' native support for fragment caching assumes that a fragm
|
|
|
18
18
|
```
|
|
19
19
|
The content is stored in the cache using a _key_ value derived from the record's `id` attribute. The key identifies where the cached content is stored. In addition, a _version_ value derived from the record's `updated_at` attribute is stored along with the content [^1]. If any attributes of the record change, the `updated_at` attribute also changes; the next time a browser requests the content, a mismatch will exist between the calculated and stored values of the version, causing the cache to expire and the fragment to be re-rendered using the current data.
|
|
20
20
|
|
|
21
|
-
[^1]: Prior to Rails 5.2, the value of `updated_at` was incorporated into the cache key rather
|
|
21
|
+
[^1]: Prior to Rails 5.2, the value of `updated_at` was incorporated into the cache key rather than the version. That behavior is still available by setting `config.active_record.cache_versioning = false` in `config/application.rb`.
|
|
22
22
|
|
|
23
23
|
For data models with a `has_one` or `has_many` association, nested (Russian Doll) caching is possible with the inner fragment representing the associated record. For example if a product has many games -
|
|
24
24
|
```
|
|
@@ -712,7 +712,7 @@ end
|
|
|
712
712
|
|
|
713
713
|
Another scenario that occasionally arises is when internal requests created in the course of executing methods defined in a `subscribe_to` block include the path to the same page that the controller is going to render anyway in the normal course of responding to the user's current browser request. In effect, that one internal request is redundant. Although it generally won't cause any real harm to send a redundant request (remember the internal request is usually dispatched asynchronously, so it won't interfere with the synchronous response), redundancy is redundancy and you may wish to avoid it.
|
|
714
714
|
|
|
715
|
-
In this case, it is possible within the controller to remove a request that has already been queued, after the application data has been created, updated or destroyed, by using the class method `Fragment.remove_queued_request`. The method takes two
|
|
715
|
+
In this case, it is possible within the controller to remove a request that has already been queued, after the application data has been created, updated or destroyed, by using the class method `Fragment.remove_queued_request`. The method takes two required keyword parameters, the path of the request to be removed and the current user object, with the latter allowing it to remove the request from only queues corresponding to the current_user's user_type, e.g.
|
|
716
716
|
|
|
717
717
|
```
|
|
718
718
|
class ProductsController < ApplicationController
|
|
@@ -732,6 +732,12 @@ class ProductsController < ApplicationController
|
|
|
732
732
|
end
|
|
733
733
|
end
|
|
734
734
|
```
|
|
735
|
+
As written above, `remove_queued_request` will remove the specified request from all queues defined for the `user_type` of the current user. If you have multiple application instances defined, a request_queue for that user_type will exist for each instance. If you only want to remove the request from the queue for a specific instance, you can include an additional optional keyword parameter `:host_url` specifiying the root_url of that instance, e.g.
|
|
736
|
+
```
|
|
737
|
+
...
|
|
738
|
+
ProductTemplate.remove_queued_request(:request_path => "/products/#{@product.id}", :user => current_user, :host_url => Fragmentary.application_root_url)
|
|
739
|
+
...
|
|
740
|
+
```
|
|
735
741
|
|
|
736
742
|
### Handling AJAX Requests
|
|
737
743
|
|
data/fragmentary.gemspec
CHANGED
|
@@ -22,7 +22,7 @@ Gem::Specification.new do |spec|
|
|
|
22
22
|
spec.bindir = "exe"
|
|
23
23
|
spec.require_paths = ["lib"]
|
|
24
24
|
|
|
25
|
-
spec.add_runtime_dependency "rails", "
|
|
25
|
+
spec.add_runtime_dependency "rails", ">= 6.0"
|
|
26
26
|
spec.add_runtime_dependency "wisper-activerecord", "~> 1.0"
|
|
27
27
|
spec.add_runtime_dependency "http", "~> 3.0.0"
|
|
28
28
|
spec.add_runtime_dependency "nokogiri"
|
data/lib/fragmentary/config.rb
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
module Fragmentary
|
|
2
2
|
|
|
3
3
|
class Config
|
|
4
|
+
|
|
4
5
|
include Singleton
|
|
6
|
+
|
|
5
7
|
attr_accessor :current_user_method, :get_sign_in_path, :post_sign_in_path, :sign_out_path,
|
|
6
|
-
:users, :default_user_type_mapping, :
|
|
7
|
-
:
|
|
8
|
+
:users, :default_user_type_mapping, :user_types, :remote_urls, :insert_timestamps,
|
|
9
|
+
:deployed_at, :release_name
|
|
10
|
+
|
|
11
|
+
attr_reader :user_types, :application_root_url_column
|
|
8
12
|
|
|
9
13
|
def initialize
|
|
10
14
|
# default
|
|
@@ -18,8 +22,7 @@ module Fragmentary
|
|
|
18
22
|
|
|
19
23
|
def session_users=(session_users)
|
|
20
24
|
raise "config.session_users must be a Hash" unless session_users.is_a?(Hash)
|
|
21
|
-
Fragmentary.parse_session_users(session_users)
|
|
22
|
-
@session_users = session_users
|
|
25
|
+
@user_types = Fragmentary.parse_session_users(session_users)
|
|
23
26
|
end
|
|
24
27
|
|
|
25
28
|
def application_root_url_column=(column_name)
|
|
@@ -33,12 +36,15 @@ module Fragmentary
|
|
|
33
36
|
|
|
34
37
|
# Parse a set of session_user options, creating session_users where needed, and return a set of user_type keys.
|
|
35
38
|
# session_users may take several forms:
|
|
36
|
-
# (1) a hash whose keys are user_type strings and whose values
|
|
37
|
-
#
|
|
38
|
-
#
|
|
39
|
+
# (1) a hash whose keys are user_type strings and whose values consist of either:
|
|
40
|
+
# (a) a hash with the form {:credentials => credentials},
|
|
41
|
+
# where 'credentials' is either a hash of parameters to be submitted when logging in or a proc that
|
|
42
|
+
# returns those parameters.
|
|
43
|
+
# (b) an array of hashes, each of the form {:credentials => credentials, :group => group_name}
|
|
44
|
+
# where the ':group' element of the hash is optional
|
|
39
45
|
# (2) an array of hashes as described in (1) above.
|
|
40
46
|
# (3) an array of user_type strings corresponding to SessionUser objects already defined.
|
|
41
|
-
# (4) an array containing a mixture of user_type strings and hashes as described in (1) above.
|
|
47
|
+
# (4) an array containing a mixture of user_type strings as described in (3) and hashes as described in (1) above.
|
|
42
48
|
# Non-hash elements that don't represent existing SessionUser objects should raise an exception. Array
|
|
43
49
|
# elements that are hashes should be parsed to create new SessionUser objects. Raise an exception on
|
|
44
50
|
# any attempt to redefine an existing user_type.
|
|
@@ -58,11 +64,15 @@ module Fragmentary
|
|
|
58
64
|
end
|
|
59
65
|
end
|
|
60
66
|
elsif session_users.is_a?(Hash)
|
|
61
|
-
session_users.each_with_object([])
|
|
62
|
-
#
|
|
63
|
-
#
|
|
67
|
+
session_users.each_with_object([]) do |(user_type, users), acc|
|
|
68
|
+
# users is either an options hash that typically looks like {:credentials => credentials} or an array of such hashes,
|
|
69
|
+
# where credentials is either a hash of parameters to be submitted at login or a proc that returns those parameters.
|
|
64
70
|
# In the latter case, the proc is executed when we actually log in to create a new session for the specified user.
|
|
65
|
-
|
|
71
|
+
users = [users] unless users.is_a?(Array)
|
|
72
|
+
users.each do |options|
|
|
73
|
+
SessionUser.create(user_type, options)
|
|
74
|
+
end
|
|
75
|
+
acc << user_type
|
|
66
76
|
end
|
|
67
77
|
end
|
|
68
78
|
end
|
data/lib/fragmentary/fragment.rb
CHANGED
|
@@ -13,13 +13,13 @@ module Fragmentary
|
|
|
13
13
|
base.class_eval do
|
|
14
14
|
include ActionView::Helpers::CacheHelper
|
|
15
15
|
|
|
16
|
-
belongs_to :parent, :class_name => name
|
|
17
|
-
belongs_to :root, :class_name => name
|
|
16
|
+
belongs_to :parent, :class_name => name, :optional => true # because a root fragment doesn't have a parent
|
|
17
|
+
belongs_to :root, :class_name => name, :optional => true # or a root_id
|
|
18
18
|
has_many :children, :class_name => name, :foreign_key => :parent_id, :dependent => :destroy
|
|
19
|
-
belongs_to :user
|
|
19
|
+
belongs_to :user, :optional => true # because only fragments that declare 'needs_user_id' require one
|
|
20
20
|
|
|
21
21
|
# Don't touch the parent when we create the child - the child was created by
|
|
22
|
-
#
|
|
22
|
+
# rendering the parent, which occured because the parent was touched, thus
|
|
23
23
|
# triggering the current request. Touching it again would result in a
|
|
24
24
|
# redundant duplicate request.
|
|
25
25
|
after_commit :touch_parent, :on => [:update, :destroy]
|
|
@@ -52,7 +52,8 @@ module Fragmentary
|
|
|
52
52
|
raise ArgumentError, "You passed Fragment #{fragment.id} to Fragment.root, but it's a child of Fragment #{fragment.parent_id}" if fragment.parent_id
|
|
53
53
|
else
|
|
54
54
|
klass, search_attributes, options = base_class.attributes(options)
|
|
55
|
-
fragment = klass.where(search_attributes).includes(:children).first_or_initialize(options);
|
|
55
|
+
fragment = klass.where(search_attributes).includes(:children).first_or_initialize(options);
|
|
56
|
+
fragment.save if fragment.new_record?
|
|
56
57
|
fragment.set_indexed_children if fragment.child_search_key
|
|
57
58
|
end
|
|
58
59
|
fragment
|
|
@@ -166,8 +167,13 @@ module Fragmentary
|
|
|
166
167
|
super
|
|
167
168
|
end
|
|
168
169
|
|
|
169
|
-
def remove_queued_request(user:, request_path:)
|
|
170
|
-
|
|
170
|
+
def remove_queued_request(host_url: nil, user:, request_path:)
|
|
171
|
+
u_type = user_type(user)
|
|
172
|
+
if host_url.is_a?(String) and (queue = request_queues[host_url][u_type])
|
|
173
|
+
queue.remove_path(request_path)
|
|
174
|
+
else
|
|
175
|
+
request_queues.each{|key, hsh| hsh[u_type].remove_path(request_path)}
|
|
176
|
+
end
|
|
171
177
|
end
|
|
172
178
|
|
|
173
179
|
def subscriber
|
|
@@ -209,7 +215,7 @@ module Fragmentary
|
|
|
209
215
|
end
|
|
210
216
|
@user_types = Fragmentary.parse_session_users(options[:session_users] || options[:types] || options[:user_types])
|
|
211
217
|
def self.user_types
|
|
212
|
-
@user_types || Fragmentary.config.
|
|
218
|
+
@user_types || Fragmentary.config.user_types
|
|
213
219
|
end
|
|
214
220
|
end
|
|
215
221
|
end
|
|
@@ -493,14 +499,15 @@ module Fragmentary
|
|
|
493
499
|
self.class.cache_store
|
|
494
500
|
end
|
|
495
501
|
|
|
496
|
-
def touch(*args, no_request: false)
|
|
502
|
+
def touch(*args, no_request: false, **kwargs)
|
|
497
503
|
@no_request = no_request # stored for use in #touch_parent via the after_commit callback
|
|
498
504
|
request_queues.each{|key, hsh| hsh.each{|key2, queue| queue << request}} if request && !no_request
|
|
499
|
-
super(*args)
|
|
505
|
+
super(*args, **kwargs)
|
|
500
506
|
end
|
|
501
507
|
|
|
502
508
|
# delete the associated cache content before destroying the fragment
|
|
503
509
|
def destroy(options = {})
|
|
510
|
+
children.each(&:destroy)
|
|
504
511
|
options.delete(:delete_matches) ? delete_matched_cache : delete_cache
|
|
505
512
|
@no_request = options.delete(:no_request) # stored for use in #touch_parent via the after_commit callback
|
|
506
513
|
super()
|
|
@@ -596,7 +603,9 @@ module Fragmentary
|
|
|
596
603
|
|
|
597
604
|
private
|
|
598
605
|
def touch_parent
|
|
599
|
-
parent
|
|
606
|
+
if parent
|
|
607
|
+
parent.touch(no_request: @no_request) unless previous_changes["memo"]
|
|
608
|
+
end
|
|
600
609
|
@no_request = false
|
|
601
610
|
end
|
|
602
611
|
|
data/lib/fragmentary/handler.rb
CHANGED
|
@@ -1,26 +1,4 @@
|
|
|
1
1
|
module Fragmentary
|
|
2
|
-
|
|
3
|
-
class HandlerSerializer < ActiveJob::Serializers::ObjectSerializer
|
|
4
|
-
|
|
5
|
-
def serialize?(arg)
|
|
6
|
-
arg.is_a? Fragmentary::Handler
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
def serialize(handler)
|
|
10
|
-
super(
|
|
11
|
-
{
|
|
12
|
-
:class_name => handler.class.name,
|
|
13
|
-
:args => handler.args
|
|
14
|
-
}
|
|
15
|
-
)
|
|
16
|
-
end
|
|
17
|
-
|
|
18
|
-
def deserialize(hsh)
|
|
19
|
-
hsh[:class_name].constantize.new(hsh[:args])
|
|
20
|
-
end
|
|
21
|
-
|
|
22
|
-
end
|
|
23
|
-
|
|
24
2
|
class Handler
|
|
25
3
|
def self.all
|
|
26
4
|
@@all
|
|
@@ -31,14 +9,14 @@ module Fragmentary
|
|
|
31
9
|
end
|
|
32
10
|
self.clear
|
|
33
11
|
|
|
34
|
-
def self.create(
|
|
12
|
+
def self.create(args)
|
|
35
13
|
@@all << (handler = self.new(args))
|
|
36
14
|
handler
|
|
37
15
|
end
|
|
38
16
|
|
|
39
17
|
attr_reader :args
|
|
40
18
|
|
|
41
|
-
def initialize(
|
|
19
|
+
def initialize(args)
|
|
42
20
|
@args = args
|
|
43
21
|
end
|
|
44
22
|
|
|
@@ -9,9 +9,7 @@ module Fragmentary
|
|
|
9
9
|
Rails.logger.info "\n***** Dispatching task for handler class #{task.class.name}"
|
|
10
10
|
task.call
|
|
11
11
|
end
|
|
12
|
-
RequestQueue.
|
|
13
|
-
queue.start
|
|
14
|
-
end
|
|
12
|
+
RequestQueue.send_all(:between => 10.seconds, :priority => 10)
|
|
15
13
|
end
|
|
16
14
|
|
|
17
15
|
end
|
|
@@ -12,7 +12,7 @@ module Fragmentary
|
|
|
12
12
|
@between = between
|
|
13
13
|
@queue_suffix = queue_suffix
|
|
14
14
|
@priority = priority
|
|
15
|
-
@between ? @queue.send_next_request : @queue.send_all_requests
|
|
15
|
+
(@between && @between.is_a?(ActiveSupport::Duration)) ? @queue.send_next_request : @queue.send_all_requests
|
|
16
16
|
end
|
|
17
17
|
|
|
18
18
|
def schedule_next
|
|
@@ -39,7 +39,9 @@ module Fragmentary
|
|
|
39
39
|
end
|
|
40
40
|
|
|
41
41
|
def after_destroy_broadcast
|
|
42
|
+
Rails.logger.info "\n***** #{start = Time.now} broadcasting :after_destroy from #{self.class.name} #{self.id}\n"
|
|
42
43
|
broadcast(:after_destroy, self)
|
|
44
|
+
Rails.logger.info "\n***** #{Time.now} broadcast :after_destroy from #{self.class.name} #{self.id} took #{(Time.now - start) * 1000} ms\n"
|
|
43
45
|
end
|
|
44
46
|
|
|
45
47
|
def after_commit_broadcast
|
|
@@ -6,15 +6,19 @@ module Fragmentary
|
|
|
6
6
|
@@all ||= []
|
|
7
7
|
end
|
|
8
8
|
|
|
9
|
-
def self.send_all(between: nil)
|
|
10
|
-
unless between
|
|
11
|
-
all.each{|q| q.start}
|
|
9
|
+
def self.send_all(delay: nil, between: nil, queue_suffix: '', priority: 0, user_group: 'default')
|
|
10
|
+
unless delay or between
|
|
11
|
+
all.each{|q| q.start(queue_suffix: queue_suffix, priority: priority, user_group: user_group)}
|
|
12
12
|
else
|
|
13
|
+
delay ||= 0.seconds
|
|
14
|
+
between ||= 0.seconds
|
|
15
|
+
unless delay.is_a? ActiveSupport::Duration
|
|
16
|
+
raise TypeError, "Fragmentary::RequestQueue.send_all requires the keyword argument :delay to be of class ActiveSupport::Duration. The value provided is of class #{delay.class.name}."
|
|
17
|
+
end
|
|
13
18
|
unless between.is_a? ActiveSupport::Duration
|
|
14
19
|
raise TypeError, "Fragmentary::RequestQueue.send_all requires the keyword argument :between to be of class ActiveSupport::Duration. The value provided is of class #{between.class.name}."
|
|
15
20
|
end
|
|
16
|
-
delay
|
|
17
|
-
all.each{|q| q.start(:delay => delay += between)}
|
|
21
|
+
all.each{|q| q.start(delay: (delay += between), queue_suffix: queue_suffix, priority: priority, user_group: user_group)}
|
|
18
22
|
end
|
|
19
23
|
end
|
|
20
24
|
|
|
@@ -57,12 +61,12 @@ module Fragmentary
|
|
|
57
61
|
@sender ||= Sender.new(self)
|
|
58
62
|
end
|
|
59
63
|
|
|
60
|
-
def send(**
|
|
61
|
-
sender.start(
|
|
64
|
+
def send(**kwargs)
|
|
65
|
+
sender.start(**kwargs)
|
|
62
66
|
end
|
|
63
67
|
|
|
64
|
-
def method_missing(method, *args)
|
|
65
|
-
sender.send(method, *args)
|
|
68
|
+
def method_missing(method, *args, **kwargs)
|
|
69
|
+
sender.send(method, *args, **kwargs)
|
|
66
70
|
end
|
|
67
71
|
|
|
68
72
|
class Sender
|
|
@@ -87,15 +91,17 @@ module Fragmentary
|
|
|
87
91
|
|
|
88
92
|
end
|
|
89
93
|
|
|
90
|
-
attr_reader :queue, :target, :delay, :between, :queue_suffix, :priority
|
|
94
|
+
attr_reader :queue, :target, :delay, :between, :queue_suffix, :priority, :user_group, :queue_name
|
|
91
95
|
|
|
92
96
|
def initialize(queue)
|
|
93
97
|
@queue = queue
|
|
94
98
|
@target = Target.new(queue.host_root_url)
|
|
99
|
+
@user_group = 'default'
|
|
100
|
+
@queue_name = @target.queue_name
|
|
95
101
|
end
|
|
96
102
|
|
|
97
103
|
def session_user
|
|
98
|
-
@session_user ||= Fragmentary::SessionUser.fetch(queue.user_type)
|
|
104
|
+
@session_user ||= Fragmentary::SessionUser.fetch(queue.user_type, user_group)
|
|
99
105
|
end
|
|
100
106
|
|
|
101
107
|
def session
|
|
@@ -103,9 +109,16 @@ module Fragmentary
|
|
|
103
109
|
end
|
|
104
110
|
|
|
105
111
|
# Send all requests, either directly or by schedule
|
|
106
|
-
|
|
112
|
+
# Note that the :between argument here represents the time between sending consecutive *requests*, whereas in RequestQueue#send_all it
|
|
113
|
+
# represents the time between starting consecutive queues.
|
|
114
|
+
# The :between argument here is deprecated. There is no :between value passed from RequestQueue.send_all to RequestQueue::Sender#start
|
|
115
|
+
def start(delay: nil, between: nil, queue_suffix: '', priority: 0, user_group: 'default')
|
|
107
116
|
Rails.logger.info "\n***** Processing request queue for user_type '#{queue.user_type}'\n"
|
|
108
|
-
@delay = delay
|
|
117
|
+
@delay = delay
|
|
118
|
+
@between = between
|
|
119
|
+
@queue_suffix = queue_suffix
|
|
120
|
+
@priority = priority
|
|
121
|
+
@user_group = user_group
|
|
109
122
|
if @delay or @between
|
|
110
123
|
schedule_requests(@delay)
|
|
111
124
|
# sending requests by schedule makes a copy of the sender and queue objects for
|
|
@@ -124,13 +137,15 @@ module Fragmentary
|
|
|
124
137
|
def send_next_request
|
|
125
138
|
if queue.size > 0
|
|
126
139
|
request = queue.next_request
|
|
127
|
-
|
|
140
|
+
parameters = (request.parameters || {}).merge(:queue_suffix => queue_suffix)
|
|
141
|
+
session.send_request(:method => request.method, :path => request.path, :parameters => parameters, :options => request.options)
|
|
128
142
|
end
|
|
129
143
|
end
|
|
130
144
|
|
|
131
145
|
private
|
|
132
146
|
|
|
133
|
-
def send_all_requests
|
|
147
|
+
def send_all_requests(user_group: 'default')
|
|
148
|
+
@user_group = user_group
|
|
134
149
|
clear_session
|
|
135
150
|
while queue.size > 0
|
|
136
151
|
send_next_request
|
|
@@ -141,7 +156,7 @@ module Fragmentary
|
|
|
141
156
|
if queue.size > 0
|
|
142
157
|
clear_session
|
|
143
158
|
job = SendRequestsJob.new(queue, delay: delay, between: between, queue_suffix: queue_suffix, priority: priority)
|
|
144
|
-
job.enqueue(:wait => delay, :queue =>
|
|
159
|
+
job.enqueue({:wait => delay, :queue => queue_name + queue_suffix, :priority => priority})
|
|
145
160
|
end
|
|
146
161
|
end
|
|
147
162
|
|
|
@@ -2,26 +2,34 @@ module Fragmentary
|
|
|
2
2
|
|
|
3
3
|
class SessionUser
|
|
4
4
|
|
|
5
|
+
attr_reader :options, :user_type
|
|
6
|
+
|
|
5
7
|
def self.all
|
|
6
|
-
@@all ||= Hash.new
|
|
8
|
+
@@all ||= Hash.new { |hsh, user_type| hsh[user_type] = Hash.new }
|
|
7
9
|
end
|
|
10
|
+
private_class_method :all
|
|
11
|
+
private_class_method :new
|
|
8
12
|
|
|
9
|
-
def self.fetch(
|
|
10
|
-
all[
|
|
13
|
+
def self.fetch(user_type, user_group = 'default')
|
|
14
|
+
all[user_type][user_group]
|
|
11
15
|
end
|
|
12
16
|
|
|
13
|
-
def
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
else
|
|
18
|
-
user
|
|
19
|
-
end
|
|
17
|
+
def self.create(user_type, options={})
|
|
18
|
+
user_group = options[:group] || options[:user_group] || 'default'
|
|
19
|
+
if user = fetch(user_type, user_group)
|
|
20
|
+
raise RangeError, "You can't redefine an existing SessionUser object: #{user_type.inspect}" unless user.options == options
|
|
20
21
|
else
|
|
21
|
-
@user_type = user_type
|
|
22
|
+
@user_type = user_type # this probably not really necessary
|
|
22
23
|
@options = options
|
|
23
|
-
|
|
24
|
+
user = new(user_type, options)
|
|
25
|
+
all[user_type].merge!(user_group => user)
|
|
24
26
|
end
|
|
27
|
+
user
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def initialize(user_type, options={})
|
|
31
|
+
@user_type = user_type # this probably not really necessary
|
|
32
|
+
@options = options
|
|
25
33
|
end
|
|
26
34
|
|
|
27
35
|
def credentials
|
|
@@ -2,19 +2,32 @@ require 'fragmentary/subscription'
|
|
|
2
2
|
|
|
3
3
|
module Fragmentary
|
|
4
4
|
|
|
5
|
-
# Each fragment subclass has a unique Subscriber instance
|
|
6
|
-
# to publishers.
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
# fragment
|
|
5
|
+
# Each fragment subclass has a unique Subscriber instance responsible for handling subscriptions
|
|
6
|
+
# to publishers. The subscriber is instantiated the first time it is referenced within the subscribe_to
|
|
7
|
+
# method called on the fragment. That method calls a method of the same name on the subscriber, which
|
|
8
|
+
# instantiates a new Subscription for each publisher it subscribes to and executes its block against
|
|
9
|
+
# the subscriber, thus defining handlers for each publisher event of interest on the subscriber,
|
|
10
|
+
# (rather than the fragment). Any other method invoked within a handler is delegated to the client, i.e.
|
|
11
|
+
# the Fragment subclass that the subscriber is responsible for.
|
|
12
|
+
#
|
|
13
|
+
# A separate subscription exists for each combination of publisher and subscriber (and thus Fragment subclass).
|
|
14
|
+
# When a subscription is instantiated for a given publisher, it registers itself with a Subscription::Proxy
|
|
15
|
+
# for that publisher. The proxy, is instantiated the first time it is referenced by a subscription to a
|
|
16
|
+
# particular publisher, and it subscribes on behalf of all its registered subscriptions to Wisper events
|
|
17
|
+
# broadcast by that publisher.
|
|
18
|
+
#
|
|
19
|
+
# The Proxy class contains the methods such as 'after_create', 'after_update' etc that are called automatically
|
|
20
|
+
# by Wisper when the publisher broacdcasts the corresponding events. These methods each invoke methods of the
|
|
21
|
+
# same name on each of proxy's registered subscriptions, and it is these that in turn invoke the methods
|
|
22
|
+
# defined by the subscribe_to blocks on the susbcriber associated with the subscription.
|
|
11
23
|
class Subscriber
|
|
12
24
|
attr_reader :client, :subscriptions
|
|
13
25
|
|
|
14
26
|
def initialize(client)
|
|
15
27
|
@client = client
|
|
16
28
|
@subscriptions = Hash.new do |h, key|
|
|
17
|
-
|
|
29
|
+
publisher = key.constantize # Ensures that the model is loaded so that the const below is defined.
|
|
30
|
+
if Object.const_defined?(key) and publisher < ActiveRecord::Base
|
|
18
31
|
h[key] = Subscription.new(publisher, self)
|
|
19
32
|
else
|
|
20
33
|
nil
|
|
@@ -76,11 +76,13 @@ module Fragmentary
|
|
|
76
76
|
|
|
77
77
|
private
|
|
78
78
|
def call_method(method, record)
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
79
|
+
if subscriber.respond_to? method
|
|
80
|
+
Rails.logger.info "***** Calling #{method.inspect} on #{subscriber.client.name} with record #{record.class.name} #{record.id}"
|
|
81
|
+
start = Time.now
|
|
82
|
+
subscriber.public_send(method, record)
|
|
83
|
+
finish = Time.now
|
|
84
|
+
Rails.logger.info "***** #{method.inspect} duration: #{(finish - start) * 1000}ms\n\n"
|
|
85
|
+
end
|
|
84
86
|
end
|
|
85
87
|
|
|
86
88
|
end
|
|
@@ -17,6 +17,7 @@ module Fragmentary
|
|
|
17
17
|
@user = user
|
|
18
18
|
@target = URI.parse(target)
|
|
19
19
|
@session.host! session_host
|
|
20
|
+
@session.https! if (@target.scheme == 'https')
|
|
20
21
|
sign_in if session_credentials
|
|
21
22
|
instance_eval(&block) if block_given?
|
|
22
23
|
end
|
|
@@ -43,6 +44,7 @@ module Fragmentary
|
|
|
43
44
|
|
|
44
45
|
def relative_url_root
|
|
45
46
|
@relative_url_root ||= Rails.application.config.relative_url_root
|
|
47
|
+
@relative_url_root ||= Rails.application.routes.default_url_options[:relative_url_root].try(:gsub, /\/$/,'')
|
|
46
48
|
end
|
|
47
49
|
|
|
48
50
|
def session_options
|
|
@@ -89,7 +91,7 @@ module Fragmentary
|
|
|
89
91
|
puts " * Sending request '#{method.to_s} #{path}'" + (!parameters.nil? ? " with #{parameters.inspect}" : "")
|
|
90
92
|
Rails.logger.info " * Sending request '#{method.to_s} #{path}'" + (!parameters.nil? ? " with #{parameters.inspect}" : "")
|
|
91
93
|
end
|
|
92
|
-
@session.send(method, path, options)
|
|
94
|
+
@session.send(method, path, **options)
|
|
93
95
|
end
|
|
94
96
|
|
|
95
97
|
def sign_out
|
data/lib/fragmentary/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,27 +1,27 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fragmentary
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Mark Thomson
|
|
8
|
-
autorequire:
|
|
8
|
+
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2026-08-17 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
|
16
16
|
requirements:
|
|
17
|
-
- - "
|
|
17
|
+
- - ">="
|
|
18
18
|
- !ruby/object:Gem::Version
|
|
19
19
|
version: '6.0'
|
|
20
20
|
type: :runtime
|
|
21
21
|
prerelease: false
|
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
|
23
23
|
requirements:
|
|
24
|
-
- - "
|
|
24
|
+
- - ">="
|
|
25
25
|
- !ruby/object:Gem::Version
|
|
26
26
|
version: '6.0'
|
|
27
27
|
- !ruby/object:Gem::Dependency
|
|
@@ -149,7 +149,7 @@ homepage: https://github.com/MarkMT/fragmentary
|
|
|
149
149
|
licenses:
|
|
150
150
|
- MIT
|
|
151
151
|
metadata: {}
|
|
152
|
-
post_install_message:
|
|
152
|
+
post_install_message:
|
|
153
153
|
rdoc_options: []
|
|
154
154
|
require_paths:
|
|
155
155
|
- lib
|
|
@@ -164,8 +164,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
164
164
|
- !ruby/object:Gem::Version
|
|
165
165
|
version: '0'
|
|
166
166
|
requirements: []
|
|
167
|
-
rubygems_version: 3.
|
|
168
|
-
signing_key:
|
|
167
|
+
rubygems_version: 3.3.22
|
|
168
|
+
signing_key:
|
|
169
169
|
specification_version: 4
|
|
170
170
|
summary: Fragment modeling and caching for Rails
|
|
171
171
|
test_files: []
|