Class: UState::Reaper

Inherits:
Object
  • Object
show all
Defined in:
lib/ustate/reaper.rb

Constant Summary collapse

DEFAULT =

By default, states die after

1000
INTERVAL =

By default, scans for old states every

10

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(index, opts = {}) ⇒ Reaper

Returns a new instance of Reaper.



15
16
17
18
19
20
21
22
23
24
25
# File 'lib/ustate/reaper.rb', line 15

def initialize(index, opts = {})
  @index = index
  @interval = opts[:interval] || INTERVAL
  @server = opts[:server]
  @targets = {}
  @lock = Mutex.new
  @compiled_targets = {}
  self.default = opts[:default] || DEFAULT

  start
end

Instance Attribute Details

#defaultObject

Returns the value of attribute default.



10
11
12
# File 'lib/ustate/reaper.rb', line 10

def default
  @default
end

#indexObject

Returns the value of attribute index.



11
12
13
# File 'lib/ustate/reaper.rb', line 11

def index
  @index
end

#intervalObject

Returns the value of attribute interval.



12
13
14
# File 'lib/ustate/reaper.rb', line 12

def interval
  @interval
end

#targetsObject

Returns the value of attribute targets.



13
14
15
# File 'lib/ustate/reaper.rb', line 13

def targets
  @targets
end

Instance Method Details

#compileObject

Transform targets into disjoint queries, ordered by age. This is kinda ugly; should do write an AST optimizer with boolean minimization if anyone starts using this feature heavily.



30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
# File 'lib/ustate/reaper.rb', line 30

def compile
  @lock.synchronize do
    @compiled_targets = {}
    
    ordered = @targets.sort do |a,b|
      # The states with the longest lifetimes must be excluded from
      # all the younger checks. Nil = +inf.
      if b[1].nil?
        1
      elsif a[1].nil?
        -1
      else
        b[1] <=> a[1]
      end
    end
    
    excluded = ordered.inject(nil) do |exclude, pair|
      # Build up a set of all queries which should last *longer* than us.
      query, age = pair
      if exclude
        if age
          @compiled_targets["(#{query}) and not (#{exclude})"] = age
        end
        "(#{query}) or (#{exclude})"
      else
        if age
          @compiled_targets[query] = age
        end
        query
      end
    end

    # Add default
    if @default
      q = if excluded
            "not (#{excluded})"
          else
            "true"
          end
      @compiled_targets[q] = @default
    end
  end
end

#delete(query) ⇒ Object

Delete states matching query



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/ustate/reaper.rb', line 80

def delete(query)
  @index.query(Query.new(string: query)).each do |state|
    @index.on_state_change(
      state,
      State.new(
        host: state.host,
        service: state.service,
        state: 'unknown',
        description: "ustate has not heard from this service since #{Time.at(state.time)}",
        time: Time.now.to_i
      )
    )
    @index.delete state
  end
end

#reap(query, age) ⇒ Object

Reap states matching query after age seconds.

The reaper is gentle; it will give any state specified to reap() the maximum possible time to live.



100
101
102
103
# File 'lib/ustate/reaper.rb', line 100

def reap(query, age)
  reap! query, age
  compile
end

#reap!(query, age) ⇒ Object



105
106
107
# File 'lib/ustate/reaper.rb', line 105

def reap!(query, age)
  @targets[query] = age
end

#startObject



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
# File 'lib/ustate/reaper.rb', line 109

def start
  @runner = Thread.new do
    loop do
      begin
        @lock.synchronize do
          @compiled_targets.each do |query, age|
            delete "(#{query}) and time < #{(Time.now - age).to_i}"
          end
        end
      rescue Exception => e
        @server.log.warn e
      end
      sleep @interval
    end
  end
end