Class: Endoscope::Agent

Inherits:
Object
  • Object
show all
Defined in:
lib/endoscope/agent.rb

Constant Summary collapse

ENDOSCOPE =
"endoscope".freeze
EvalTimeout =
Class.new(Timeout::Error)

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(dyno_name, redis_options) ⇒ Agent

Returns a new instance of Agent.



16
17
18
19
# File 'lib/endoscope/agent.rb', line 16

def initialize(dyno_name, redis_options)
  @dyno_name = dyno_name
  @redis_options = redis_options || default_redis_options
end

Instance Attribute Details

#dyno_nameObject (readonly)

Returns the value of attribute dyno_name.



14
15
16
# File 'lib/endoscope/agent.rb', line 14

def dyno_name
  @dyno_name
end

#redis_optionsObject (readonly)

Returns the value of attribute redis_options.



14
15
16
# File 'lib/endoscope/agent.rb', line 14

def redis_options
  @redis_options
end

Instance Method Details

#agent_listenerObject



32
33
34
35
36
37
38
39
40
# File 'lib/endoscope/agent.rb', line 32

def agent_listener
  Thread.current[:name] = ENDOSCOPE
  begin
    wait_for_commands
  rescue => e
    puts e.inspect
    puts e.backtrace.join("\n")
  end
end

#capture_streamsObject



77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
# File 'lib/endoscope/agent.rb', line 77

def capture_streams
  $old_stdout = $stdout
  $old_stderr = $stderr

  out = StringIO.new
  $stdout = out
  $stderr = out
  yield(out)

  out.rewind
  out.read
ensure
  $stdout = $old_stdout
  $stderr = $old_stderr
end

#command_received(command) ⇒ Object



53
54
55
56
57
58
# File 'lib/endoscope/agent.rb', line 53

def command_received(command)
  puts "ns=endoscope at=command_received"
  to_eval = command.fetch('command')
  result = evaluate(to_eval)
  Transport.new(redis_options).publish_response(command, dyno_name, result)
end

#default_redis_optionsObject



21
22
23
24
25
26
# File 'lib/endoscope/agent.rb', line 21

def default_redis_options
  {
    url: ENV['ENDOSCOPE_REDIS_URL'] || 'redis://127.0.0.1:6379/',
    namespace: ENV['ENDOSCOPE_REDIS_NAMESPACE']
  }
end

#evaluate(ruby) ⇒ Object



62
63
64
65
66
67
68
69
70
71
72
73
74
75
# File 'lib/endoscope/agent.rb', line 62

def evaluate(ruby)
  capture_streams do |out|
    begin
      Timeout.timeout(10, EvalTimeout) do
        # rubocop:disable Eval
        res = eval(ruby, TOPLEVEL_BINDING, 'remote_command')
        # rubocop:enable Eval
        out.puts res.inspect
      end
    rescue Exception => e
      out.puts(e.inspect, *e.backtrace)
    end
  end
end

#startObject



28
29
30
# File 'lib/endoscope/agent.rb', line 28

def start
  Thread.new(&method(:agent_listener))
end

#wait_for_commandsObject



42
43
44
45
46
47
48
49
50
51
# File 'lib/endoscope/agent.rb', line 42

def wait_for_commands
  transport = Transport.new(redis_options)
  transport.wait_for_commands(dyno_name) do |command|
    command_received(command)
  end
rescue Transport::ConnectionError => error
  puts "ns=endoscope at=wait_for_commands error=#{error} reconnect_in=1s"
  sleep 1
  retry
end