Ravn::Tactical::

ChangeRunner class

Actor that continually tries to run pending changes on nodes in the current kit.

Constants

LOOP_TIME

Number of seconds between runs

Attributes

thread R

The Thread that is started when running

Public Class Methods

new()

Create a new ChangeRunner.

   # File lib/ravn/tactical/change_runner.rb
44 def initialize
45     @thread = nil
46     @running = false
47 end
run_until_complete()

Start an instance of the ChangeRunner and run it until all changes are completed.

   # File lib/ravn/tactical/change_runner.rb
38 def self::run_until_complete
39     self.new.run_until_complete
40 end
start()

Start an instance of the ChangeRunner and return the resulting Thread.

   # File lib/ravn/tactical/change_runner.rb
24 def self::start
25     @instance ||= self.new.start
26     return @instance.thread
27 end
stop()

Stop the running instance of the ChangeRunner (if there is one)

   # File lib/ravn/tactical/change_runner.rb
31 def self::stop
32     @instance&.stop
33 end

Public Instance Methods

run_change( change )

Run the specified change, returning a truthy value if it runs successfully.

    # File lib/ravn/tactical/change_runner.rb
149 def run_change( change )
150     op = change.operation
151 
152     op.before_run( change.node )
153     response = Ravn::Tactical::Kit.run_change( change )
154     result = op.after_run( change.node, response )
155     self.log.debug "Result is: %p" % [ result ]
156 
157     return result
158 rescue => err
159     self.log.error "%p while running %p: %s" % [ err.class, change, err.message ]
160     self.log.debug { err.backtrace.join("\n") }
161 
162     return nil
163 end
run_pending_changes()

Run any pending changes for nodes which are discoverable, skipping any that aren’t online.

    # File lib/ravn/tactical/change_runner.rb
102 def run_pending_changes
103     dataset = Ravn::Tactical::Change.earliest_for_each_node
104     start = Ravn.monotonic_time
105 
106     self.log.info "Running %d pending changes" % [ dataset.count ]
107     dataset.each do |change|
108         node = change.node
109         node.update_discovery_info
110         next unless node.online?
111 
112         self.log.info "running: %p" % [ change ]
113         self.try_change( change )
114     end
115 
116     duration = Ravn.monotonic_time - start
117     self.log.debug "  run took %0.5s" % [ duration ]
118 
119     if (remainder = LOOP_TIME - duration) > 0
120         sleep( remainder )
121     end
122 end
run_until_complete()

Start running changes and exit once the queue is empty.

   # File lib/ravn/tactical/change_runner.rb
83 def run_until_complete
84     self.running = true
85     self.run_pending_changes until Ravn::Tactical::Change.empty?
86     self.running = false
87 end
running()

True if the running is running.

   # File lib/ravn/tactical/change_runner.rb
60 attr_predicate_accessor :running
start()

Start trying to run changes on visible CPs.

   # File lib/ravn/tactical/change_runner.rb
64 def start
65     self.log.info "Starting change runner."
66     @thread = Thread.new( &self.method(:start_running_changes) )
67 
68     return self
69 end
start_running_changes()

Start trying to run pending changes.

   # File lib/ravn/tactical/change_runner.rb
91 def start_running_changes
92     Thread.current.name = "Change Runner loop" unless Thread.current == Thread.main
93 
94     self.running = true
95 
96     self.run_pending_changes while self.running?
97 end
stop()

Stop running changes.

   # File lib/ravn/tactical/change_runner.rb
73 def stop
74     self.log.info "Stopping change runner."
75     self.running = false
76 
77     @thread.join( 2 ) if @thread&.alive?
78     @thread = nil
79 end
try_change( change )

Try to run the given change, removing it if it runs successfully.

    # File lib/ravn/tactical/change_runner.rb
126 def try_change( change )
127     # :TODO: Might have to do different transactional consistency, depending
128     # on how long operations end up running, especially if the target CP isn't
129     # on the network...
130     change.db.transaction do
131         result = self.run_change( change )
132 
133         if result
134             self.log.info "%p succeeded." % [ change ]
135             self.log.debug {
136                 "Results:\n%p" % [ result ]
137             }
138             change.delete
139         else
140             self.log.error "%p failed." % [ change ]
141             raise Sequel::Rollback, "%p failed." % [ change ]
142         end
143     end
144 end