Class: Trailblazer::Developer::Trace::Snapshot

Inherits:
Struct
  • Object
show all
Defined in:
lib/trailblazer/developer/trace/snapshot.rb,
lib/trailblazer/developer/trace/snapshot/value.rb,
lib/trailblazer/developer/trace/snapshot/versions.rb

Overview

WARNING: the interfaces here are subject to change, we’re still experimenting

with the architecture of tracing, and a healthy balance of performance/memory
and clean design.

A Snapshot comprises of data captured before of after a “step”. This usually includes a ctx snapshot, variable versions and a returned signal for after-step snapshots.

Note that Before and After are generic concepts know to Trace::Present and Debugger.

Snapshot::After{

signal: <End.Success>
ctx_snapshot: Snapshot::Ctx{
  variable_versions: [:current_user, 0], [:model, 0]
}

}

Defined Under Namespace

Classes: Value, Versions

Constant Summary collapse

Before =
Class.new(Snapshot)
After =
Class.new(Snapshot)

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Attribute Details

#activityObject

Returns the value of attribute activity

Returns:

  • (Object)

    the current value of activity



18
19
20
# File 'lib/trailblazer/developer/trace/snapshot.rb', line 18

def activity
  @activity
end

#dataObject

Returns the value of attribute data

Returns:

  • (Object)

    the current value of data



18
19
20
# File 'lib/trailblazer/developer/trace/snapshot.rb', line 18

def data
  @data
end

#taskObject

Returns the value of attribute task

Returns:

  • (Object)

    the current value of task



18
19
20
# File 'lib/trailblazer/developer/trace/snapshot.rb', line 18

def task
  @task
end

Class Method Details

.after_snapshooter(wrap_ctx, _) ⇒ Object

Serialize all ctx variables at the very end of taskWrap, after Out().



49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/trailblazer/developer/trace/snapshot.rb', line 49

def self.after_snapshooter(wrap_ctx, _)
  snapshot_before             = wrap_ctx[:snapshot_before]
  returned_ctx, flow_options  = wrap_ctx[:return_args]

  changeset, new_versions = snapshot_for(returned_ctx, **flow_options)

  data = {
    ctx_variable_changeset: changeset,
    signal:                 wrap_ctx[:return_signal],
    snapshot_before:        snapshot_before, # add this so we know who belongs together.
  }

  return data, new_versions
end

.before_snapshooter(wrap_ctx, ctx, flow_options), _) ⇒ Object

Serialize all ctx variables before call_task. This is run just before call_task, after In().



38
39
40
41
42
43
44
45
46
# File 'lib/trailblazer/developer/trace/snapshot.rb', line 38

def self.before_snapshooter(wrap_ctx, ((ctx, flow_options), _))
  changeset, new_versions = snapshot_for(ctx, **flow_options)

  data = {
    ctx_variable_changeset: changeset,
  }

  return data, new_versions
end

.call(ctx_snapshooter, wrap_config, ctx, flow_options), circuit_options) ⇒ Object



23
24
25
26
27
28
29
30
31
32
33
34
# File 'lib/trailblazer/developer/trace/snapshot.rb', line 23

def self.call(ctx_snapshooter, wrap_config, ((ctx, flow_options), circuit_options))
  # DISCUSS: grab the {snapshooter} here from flow_options, instead of in Trace.capture_args?
  changeset, new_versions = ctx_snapshooter.call(wrap_config, [[ctx, flow_options], circuit_options])

  snapshot = new( # either Before or After.
    wrap_config[:task],
    circuit_options[:activity],
    changeset
  ).freeze

  return snapshot, new_versions
end

.snapshot_ctx_for(snapshot, variable_versions) ⇒ Object

Snapshot::Ctx keeps an inspected version of each ctx variable. We figure out if a variable has changed by using ‘variable.hash` (works even with deeply nested structures).

Key idea here is to have minimum work at operation-runtime. Specifics like figuring out what has changed can be done when using the debugger.

By keeping “old” versions, we get three benefits.

  1. We only need to call inspect once on a traced variable. Especially when variables are complex structures or strings, this dramatically speeds up tracing, from same-ish to factor 5!

  2. The content sent to our debugger is much smaller which reduces network load and storage space.

  3. Presentation becomes simpler as we “know” what variable has changed.

Possible problems: when variablevariable.hash returns the same key even though the

data has changed.

DISCUSS: speed up by checking mutable, only? DISCUSS: we currently only use this for testing. DISCUSS: this has knowledge about Trailblazer::Developer::Trace::Stack internals.

This is for the “rendering” layer.



28
29
30
31
32
33
34
35
36
37
38
39
40
# File 'lib/trailblazer/developer/trace/snapshot/versions.rb', line 28

def self.snapshot_ctx_for(snapshot, variable_versions)
  variable_versions = variable_versions.instance_variable_get(:@variables)

  snapshot.data[:ctx_variable_changeset].collect do |name, hash, has_changed|
    [
      name,
      {
        value:        variable_versions[name][hash],
        has_changed:  !!has_changed,
      }
    ]
  end.to_h
end

.snapshot_for(ctx, value_snapshooter:, stack:) ⇒ Object



64
65
66
67
68
# File 'lib/trailblazer/developer/trace/snapshot.rb', line 64

def self.snapshot_for(ctx, value_snapshooter:, stack:, **)
  variable_versions = stack.variable_versions

  variable_versions.changeset_for(ctx, value_snapshooter: value_snapshooter) # return {changeset, new_versions}
end