Module: Pgbus::CurrentAttributes

Defined in:
lib/pgbus/current_attributes.rb

Overview

Persists ActiveSupport::CurrentAttributes across enqueue → perform (issue #430).

capture snapshots the assigned attributes of every persisted class (config.current_attributes: :auto, an explicit list, or per-class only:/except: filters) serialized through ActiveJob::Arguments — so GlobalID models, Symbols, Times round-trip like job arguments and fall under the allowed_global_id_models allowlist on the way back. An attribute holding an unpersisted record is skipped with a debug log (no id → no GlobalID → it could never be restored; see #reject_unpersisted). restore nests klass.set(attrs) for the duration of a block.

The ActiveJob side (Pgbus::ActiveJob::CurrentAttributes) calls capture from serialize and restore around perform_now, so the hop works under the pgbus worker and under Rails' :test / :inline adapters alike.

Constant Summary collapse

METADATA_KEY =
"pgbus_current"

Class Method Summary collapse

Class Method Details

.capture(config = Pgbus.configuration, override: nil) ⇒ Object

{ "Current" => serialized_attrs, ... } or nil when there is nothing to persist. override is a per-job-class spec (false disables; an Array/Hash replaces the config's list for this job).



33
34
35
36
37
38
39
40
41
42
43
44
45
46
# File 'lib/pgbus/current_attributes.rb', line 33

def capture(config = Pgbus.configuration, override: nil)
  return nil if override == false
  return nil unless override || enabled?(config)

  captured = {}
  persisted_specs(config, override: override).each do |spec|
    klass = resolve_class(spec[:name]) or next
    attrs = reject_unpersisted(klass, filter_attrs(klass.attributes, spec))
    next if attrs.empty?

    captured[klass.name] = serialize_attrs(klass, attrs)
  end
  captured.empty? ? nil : captured
end

.enabled?(config = Pgbus.configuration) ⇒ Boolean

Returns:

  • (Boolean)


26
27
28
# File 'lib/pgbus/current_attributes.rb', line 26

def enabled?(config = Pgbus.configuration)
  !config.current_attributes.nil?
end

.normalize(value) ⇒ Object

Config/override value → nil | :auto | [{ name:, only:, except: }]. Raises Pgbus::ConfigurationError for anything else.



64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/pgbus/current_attributes.rb', line 64

def normalize(value)
  case value
  when nil then nil
  when :auto then :auto
  when Array then value.map { |entry| class_spec(entry, {}) }
  when Hash then value.map { |entry, filters| class_spec(entry, filters) }
  else
    raise Pgbus::ConfigurationError,
          "current_attributes must be nil, :auto, an Array of CurrentAttributes classes/names, " \
          "or a Hash of class/name => { only: [...] } | { except: [...] } (got #{value.inspect})"
  end
end

.persisted_specs(config = Pgbus.configuration, override: nil) ⇒ Object

Normalized [{ name:, only:, except: }] for the config (or override).



78
79
80
81
82
83
84
85
86
# File 'lib/pgbus/current_attributes.rb', line 78

def persisted_specs(config = Pgbus.configuration, override: nil)
  source = override.nil? ? config.current_attributes : normalize(override)
  return [] if source.nil? || source == false
  return source unless source == :auto

  ActiveSupport::CurrentAttributes.descendants.filter_map do |klass|
    { name: klass.name, only: nil, except: nil } if klass.name
  end
end

.restore(stored, &block) ⇒ Object

Set every stored class's attributes for the block; previous values come back afterwards (ActiveSupport::CurrentAttributes#set semantics).



50
51
52
53
54
55
56
57
58
59
60
# File 'lib/pgbus/current_attributes.rb', line 50

def restore(stored, &block)
  return yield if stored.nil? || stored.empty?

  stored.reduce(block) do |inner, (name, attrs)|
    klass = resolve_class(name)
    next inner unless klass

    values = deserialize_attrs(klass, attrs)
    -> { klass.set(values) { inner.call } }
  end.call
end