Module: Familia::Features::Housekeeping::ModelClassMethods
- Defined in:
- lib/familia/features/housekeeping.rb
Overview
Housekeeping::ModelClassMethods
Instance Method Summary collapse
-
#chore(name) {|obj| ... } ⇒ Proc
Register a chore by name.
-
#chores ⇒ Hash{Symbol => Proc}
Registered chores in registration order.
-
#run_chores!(chore_name: nil, limit: nil, batch_size: DEFAULT_BATCH_SIZE) ⇒ Hash
Run registered chores against every record reachable via the
instancesclass-level sorted set.
Instance Method Details
#chore(name) {|obj| ... } ⇒ Proc
Register a chore by name. The block receives the instance.
68 69 70 71 72 73 |
# File 'lib/familia/features/housekeeping.rb', line 68 def chore(name, &block) raise ArgumentError, 'chore name required' if name.nil? || name.to_s.empty? raise ArgumentError, "chore #{name.inspect} requires a block" unless block chores[name.to_sym] = block end |
#chores ⇒ Hash{Symbol => Proc}
Registered chores in registration order. Subclasses inherit a copy of their parent's chores on first access, so registering a new chore on a subclass does not mutate the parent.
80 81 82 83 84 85 86 |
# File 'lib/familia/features/housekeeping.rb', line 80 def chores @chores ||= if superclass.respond_to?(:chores) superclass.chores.dup else {} end end |
#run_chores!(chore_name: nil, limit: nil, batch_size: DEFAULT_BATCH_SIZE) ⇒ Hash
Run registered chores against every record reachable via the
instances class-level sorted set. Records are loaded in pipelined
batches (load_multi) and each chore is executed per record with
error isolation -- one failing chore call does not abort the run.
Stats shape:
{ model: 'User', scanned: 4200, chores: { downcase_email: { modified: 37, errors: 0 }, default_timezone: { modified: 102, errors: 1 }, }, }
The modified counter increments when the chore block returns a
truthy value (the conventional "modified" signal). The errors
counter increments when the chore block raises; the exception is
logged via Familia.warn and iteration continues.
Requires the class to expose an instances collection (Horreum's
default class-level sorted set) and load_multi (Horreum default).
119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
# File 'lib/familia/features/housekeeping.rb', line 119 def run_chores!(chore_name: nil, limit: nil, batch_size: DEFAULT_BATCH_SIZE) unless respond_to?(:instances) && respond_to?(:load_multi) raise ArgumentError, "#{name} cannot run_chores! without instances and load_multi" end chore_keys = resolve_chore_keys(chore_name) stats = chore_keys.to_h { |key| [key, { modified: 0, errors: 0 }] } scanned = 0 instances.to_a.each_slice(batch_size) do |batch_ids| break if limit && scanned >= limit batch_ids = batch_ids.take(limit - scanned) if limit records = load_multi(batch_ids).compact records.each do |record| scanned += 1 chore_keys.each do |key| begin stats[key][:modified] += 1 if record.do_chore!(key) rescue StandardError => e stats[key][:errors] += 1 Familia.warn "[run_chores!] #{name}##{record.identifier} chore=#{key} failed: #{e.}" end end end end { model: name, scanned: scanned, chores: stats } end |