Class: Upkeep::Runtime::Recorder
- Inherits:
-
Object
- Object
- Upkeep::Runtime::Recorder
- Defined in:
- lib/upkeep/runtime.rb
Defined Under Namespace
Classes: RefusedBoundary
Constant Summary collapse
- REQUEST_NODE_ID =
:request
Instance Attribute Summary collapse
-
#graph ⇒ Object
readonly
Returns the value of attribute graph.
-
#refused_boundaries ⇒ Object
readonly
Returns the value of attribute refused_boundaries.
Class Method Summary collapse
Instance Method Summary collapse
- #ambient_replay_inputs_for(owner_id) ⇒ Object
- #current_frame ⇒ Object
- #current_owner ⇒ Object
- #flush_pending_dependencies(owner_id = nil) ⇒ Object
- #identity_profile(frame_id) ⇒ Object
- #identity_signature(frame_id) ⇒ Object
-
#initialize(graph: nil, profile: false) ⇒ Recorder
constructor
A new instance of Recorder.
- #profile_counts ⇒ Object
- #profile_timings ⇒ Object
- #reactive? ⇒ Boolean
- #record_ambient_replay_input(source, key, value) ⇒ Object
- #record_dependency(dependency) ⇒ Object
- #record_relation_provenance(collection, model_name:, analysis:) ⇒ Object
- #refuse_boundary(reason:, message:, suggestions:, source:) ⇒ Object
- #relation_provenance_for(collection) ⇒ Object
- #subscription_shape(request_signature: nil) ⇒ Object
- #to_h(dependencies: :all) ⇒ Object
- #to_persistent_h ⇒ Object
- #with_frame(frame_id, metadata) ⇒ Object
Constructor Details
#initialize(graph: nil, profile: false) ⇒ Recorder
Returns a new instance of Recorder.
82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/upkeep/runtime.rb', line 82 def initialize(graph: nil, profile: false) @frame_stack = [] @graph = graph || DAG::Graph.new @profile = profile @profile_timings = Hash.new(0.0) @profile_counts = Hash.new(0) @refused_boundaries = [] @ambient_replay_inputs_by_owner = Hash.new do |owners, owner_id| owners[owner_id] = Hash.new { |sources, source| sources[source] = {} } end @pending_dependencies_by_owner = Hash.new { |owners, owner_id| owners[owner_id] = {} } @relation_provenance_by_collection_id = {} @graph.add_node(REQUEST_NODE_ID, kind: :request, payload: {}) unless @graph.node?(REQUEST_NODE_ID) @subscription_shape_trace = DAG::SubscriptionShape::Trace.new(graph_version: @graph.version) end |
Instance Attribute Details
#graph ⇒ Object (readonly)
Returns the value of attribute graph.
80 81 82 |
# File 'lib/upkeep/runtime.rb', line 80 def graph @graph end |
#refused_boundaries ⇒ Object (readonly)
Returns the value of attribute refused_boundaries.
80 81 82 |
# File 'lib/upkeep/runtime.rb', line 80 def refused_boundaries @refused_boundaries end |
Class Method Details
.from_h(snapshot) ⇒ Object
98 99 100 101 |
# File 'lib/upkeep/runtime.rb', line 98 def self.from_h(snapshot) snapshot = Dependencies.symbolize_keys(snapshot) new(graph: DAG::Graph.from_h(snapshot.fetch(:graph))) end |
Instance Method Details
#ambient_replay_inputs_for(owner_id) ⇒ Object
165 166 167 168 169 |
# File 'lib/upkeep/runtime.rb', line 165 def ambient_replay_inputs_for(owner_id) @ambient_replay_inputs_by_owner.fetch(owner_id, {}).each_with_object({}) do |(source, values), inputs| inputs[source] = values.dup end end |
#current_frame ⇒ Object
213 214 215 |
# File 'lib/upkeep/runtime.rb', line 213 def current_frame @frame_stack.last end |
#current_owner ⇒ Object
217 218 219 |
# File 'lib/upkeep/runtime.rb', line 217 def current_owner current_frame || REQUEST_NODE_ID end |
#flush_pending_dependencies(owner_id = nil) ⇒ Object
133 134 135 136 137 138 139 140 141 |
# File 'lib/upkeep/runtime.rb', line 133 def flush_pending_dependencies(owner_id = nil) if owner_id flush_pending_dependencies_for(owner_id) else @pending_dependencies_by_owner.keys.each { |pending_owner_id| flush_pending_dependencies_for(pending_owner_id) } end ensure @pending_dependencies_by_owner.delete(owner_id) if owner_id end |
#identity_profile(frame_id) ⇒ Object
221 222 223 224 |
# File 'lib/upkeep/runtime.rb', line 221 def identity_profile(frame_id) flush_pending_dependencies identity_dependencies_for(frame_id).map(&:to_h) end |
#identity_signature(frame_id) ⇒ Object
226 227 228 229 230 231 232 |
# File 'lib/upkeep/runtime.rb', line 226 def identity_signature(frame_id) flush_pending_dependencies identity_dependencies = identity_dependencies_for(frame_id) return "public" if identity_dependencies.empty? Digest::SHA256.hexdigest(identity_dependencies.map(&:identity_key).sort_by(&:inspect).inspect)[0, 16] end |
#profile_counts ⇒ Object
205 206 207 |
# File 'lib/upkeep/runtime.rb', line 205 def profile_counts @profile_counts.dup end |
#profile_timings ⇒ Object
201 202 203 |
# File 'lib/upkeep/runtime.rb', line 201 def profile_timings @profile_timings.transform_values { |value| value.round(3) } end |
#reactive? ⇒ Boolean
209 210 211 |
# File 'lib/upkeep/runtime.rb', line 209 def reactive? @refused_boundaries.empty? end |
#record_ambient_replay_input(source, key, value) ⇒ Object
158 159 160 161 162 163 |
# File 'lib/upkeep/runtime.rb', line 158 def record_ambient_replay_input(source, key, value) profile_count(:recorder_ambient_replay_input_count) profile_timing(:recorder_ambient_replay_input_ms) do @ambient_replay_inputs_by_owner[current_owner][source.to_sym][key.to_s] = value end end |
#record_dependency(dependency) ⇒ Object
143 144 145 146 147 148 149 |
# File 'lib/upkeep/runtime.rb', line 143 def record_dependency(dependency) profile_count(:recorder_dependency_count) profile_timing(:recorder_dependency_ms) do owner_id = current_owner @pending_dependencies_by_owner[owner_id][dependency.cache_key] ||= dependency end end |
#record_relation_provenance(collection, model_name:, analysis:) ⇒ Object
171 172 173 174 175 176 177 178 179 |
# File 'lib/upkeep/runtime.rb', line 171 def record_relation_provenance(collection, model_name:, analysis:) return unless collection && analysis profile_count(:recorder_relation_provenance_count) profile_timing(:recorder_relation_provenance_ms) do @relation_provenance_by_collection_id[collection.object_id] = RelationProvenance.new(model_name.to_s, analysis) end end |
#refuse_boundary(reason:, message:, suggestions:, source:) ⇒ Object
185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 |
# File 'lib/upkeep/runtime.rb', line 185 def refuse_boundary(reason:, message:, suggestions:, source:) profile_count(:recorder_refused_boundary_count) profile_timing(:recorder_refused_boundary_ms) do boundary = RefusedBoundary.new( reason.to_s, .to_s, Array(suggestions).map(&:to_s), source.to_s ) return false if @refused_boundaries.include?(boundary) @refused_boundaries << boundary true end end |
#relation_provenance_for(collection) ⇒ Object
181 182 183 |
# File 'lib/upkeep/runtime.rb', line 181 def relation_provenance_for(collection) @relation_provenance_by_collection_id[collection.object_id] if collection end |
#subscription_shape(request_signature: nil) ⇒ Object
151 152 153 154 155 156 |
# File 'lib/upkeep/runtime.rb', line 151 def subscription_shape(request_signature: nil) flush_pending_dependencies return @subscription_shape_trace.subscription_shape(request_signature: request_signature) if @subscription_shape_trace.covers?(@graph) DAG::SubscriptionShape.from_graph(@graph, request_signature: request_signature) end |
#to_h(dependencies: :all) ⇒ Object
103 104 105 106 |
# File 'lib/upkeep/runtime.rb', line 103 def to_h(dependencies: :all) flush_pending_dependencies { graph: graph.to_h(dependencies: dependencies) } end |
#to_persistent_h ⇒ Object
108 109 110 |
# File 'lib/upkeep/runtime.rb', line 108 def to_persistent_h to_h(dependencies: :identity) end |
#with_frame(frame_id, metadata) ⇒ Object
112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 |
# File 'lib/upkeep/runtime.rb', line 112 def with_frame(frame_id, ) profile_count(:recorder_frame_count) parent_id = nil profile_timing(:recorder_frame_ms) do invalidate_subscription_shape_trace_if_needed parent_id = current_owner @graph.add_node(frame_id, kind: :frame, payload: ) @graph.add_edge(parent_id, frame_id, reason: :contains) profile_timing(:recorder_shape_trace_ms) do @subscription_shape_trace.record_frame(frame_id, , parent_id: parent_id, graph_version: @graph.version) end end @frame_stack.push(frame_id) begin yield ensure flush_pending_dependencies(frame_id) @frame_stack.pop end end |