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
- #replace_scope(scope_id, replacement) ⇒ 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
182 183 184 185 186 |
# File 'lib/upkeep/runtime.rb', line 182 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
230 231 232 |
# File 'lib/upkeep/runtime.rb', line 230 def current_frame @frame_stack.last end |
#current_owner ⇒ Object
234 235 236 |
# File 'lib/upkeep/runtime.rb', line 234 def current_owner current_frame || REQUEST_NODE_ID end |
#flush_pending_dependencies(owner_id = nil) ⇒ Object
150 151 152 153 154 155 156 157 158 |
# File 'lib/upkeep/runtime.rb', line 150 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
238 239 240 241 |
# File 'lib/upkeep/runtime.rb', line 238 def identity_profile(frame_id) flush_pending_dependencies identity_dependencies_for(frame_id).map(&:to_h) end |
#identity_signature(frame_id) ⇒ Object
243 244 245 246 247 248 249 |
# File 'lib/upkeep/runtime.rb', line 243 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
222 223 224 |
# File 'lib/upkeep/runtime.rb', line 222 def profile_counts @profile_counts.dup end |
#profile_timings ⇒ Object
218 219 220 |
# File 'lib/upkeep/runtime.rb', line 218 def profile_timings @profile_timings.transform_values { |value| value.round(3) } end |
#reactive? ⇒ Boolean
226 227 228 |
# File 'lib/upkeep/runtime.rb', line 226 def reactive? @refused_boundaries.empty? end |
#record_ambient_replay_input(source, key, value) ⇒ Object
175 176 177 178 179 180 |
# File 'lib/upkeep/runtime.rb', line 175 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
160 161 162 163 164 165 166 |
# File 'lib/upkeep/runtime.rb', line 160 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
188 189 190 191 192 193 194 195 196 |
# File 'lib/upkeep/runtime.rb', line 188 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
202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 |
# File 'lib/upkeep/runtime.rb', line 202 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
198 199 200 |
# File 'lib/upkeep/runtime.rb', line 198 def relation_provenance_for(collection) @relation_provenance_by_collection_id[collection.object_id] if collection end |
#replace_scope(scope_id, replacement) ⇒ Object
103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/upkeep/runtime.rb', line 103 def replace_scope(scope_id, replacement) replacement.graph.dependencies_for(REQUEST_NODE_ID).each do |dependency| replacement.graph.add_dependency(scope_id, dependency) end composed = if graph.node?(scope_id) graph.replace_subgraph(scope_id, replacement.graph) else graph.attach_subgraph( scope_id, replacement.graph, parent_id: REQUEST_NODE_ID ) end self.class.new(graph: composed) end |
#subscription_shape(request_signature: nil) ⇒ Object
168 169 170 171 172 173 |
# File 'lib/upkeep/runtime.rb', line 168 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
120 121 122 123 |
# File 'lib/upkeep/runtime.rb', line 120 def to_h(dependencies: :all) flush_pending_dependencies { graph: graph.to_h(dependencies: dependencies) } end |
#to_persistent_h ⇒ Object
125 126 127 |
# File 'lib/upkeep/runtime.rb', line 125 def to_persistent_h to_h(dependencies: :identity) end |
#with_frame(frame_id, metadata) ⇒ Object
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/upkeep/runtime.rb', line 129 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 |