forked from criteo/consul-templaterb
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathconsul_template_engine.rb
130 lines (122 loc) · 5.1 KB
/
consul_template_engine.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
require 'consul/async/utilities'
require 'consul/async/consul_endpoint'
require 'consul/async/json_endpoint'
require 'consul/async/vault_endpoint'
require 'consul/async/consul_template'
require 'consul/async/consul_template_render'
require 'em-http'
require 'erb'
module Consul
module Async
# The Engine keeps tracks of all templates, handle hot-reload of files if needed
# as well as ticking the clock to compute state of templates periodically.
class ConsulTemplateEngine
attr_reader :template_manager, :hot_reload_failure, :template_frequency, :debug_memory, :result, :templates
attr_writer :hot_reload_failure, :template_frequency, :debug_memory
def initialize
@templates = []
@template_callbacks = []
@hot_reload_failure = 'die'
@all_templates_rendered = false
@template_frequency = 1
@periodic_started = false
@debug_memory = false
@result = 0
@last_memory_state = build_memory_info
@start = Time.now
end
def build_memory_info
s = GC.stat
{
pages: s[:total_allocated_pages] - s[:total_freed_pages],
objects: s[:total_allocated_objects] - s[:total_freed_objects],
time: Time.now.utc
}
end
def add_template_callback(&block)
@template_callbacks << block
end
def add_template(source, dest, params = {})
@templates.push([source, dest, params])
end
# Run templating engine once
def do_run(template_manager, template_renders)
unless template_manager.running
::Consul::Async::Debug.puts_info '[FATAL] TemplateManager has been stopped, stopping everything'
@result = 3
EventMachine.stop
return
end
results = template_renders.map(&:run)
all_ready = results.all?(&:ready?)
if !@all_templates_rendered && all_ready
@all_templates_rendered = true
cur_time = Time.now
::Consul::Async::Debug.puts_info "First rendering of #{results.count} templates completed in #{cur_time - @start}s at #{cur_time}. "
end
begin
@template_callbacks.each do |c|
c.call([all_ready, template_manager, results])
end
rescue StandardError => e
::Consul::Async::Debug.puts_error "callback error: #{e.inspect}"
raise e
end
rescue Consul::Async::InvalidTemplateException => e
warn "[FATAL]#{e}"
template_manager.terminate
@result = 1
EventMachine.stop
rescue StandardError => e
warn "[FATAL] Error occured: #{e.inspect} - #{e.backtrace.join("\n\t")}"
template_manager.terminate
@result = 2
EventMachine.stop
end
# Run template engine as fast as possible until first rendering occurs
def do_run_fast(template_manager, template_renders)
do_run(template_manager, template_renders)
return if @all_templates_rendered || @periodic_started
# We continue if rendering not done and periodic not started
EventMachine.next_tick do
do_run_fast(template_manager, template_renders)
end
end
def run(template_manager)
@template_manager = template_manager
EventMachine.run do
template_renders = []
@templates.each do |template_file, output_file, params|
template_renders << Consul::Async::ConsulTemplateRender.new(template_manager, template_file, output_file,
hot_reload_failure: hot_reload_failure,
params: params)
end
# Initiate first run immediately to speed up rendering
EventMachine.next_tick do
do_run_fast(template_manager, template_renders)
end
EventMachine.add_periodic_timer(template_frequency) do
@periodic_started = true
do_run(template_manager, template_renders)
if debug_memory
GC.start
new_memory_state = build_memory_info
diff_allocated = new_memory_state[:pages] - @last_memory_state[:pages]
diff_num_objects = new_memory_state[:objects] - @last_memory_state[:objects]
if diff_allocated != 0 || diff_num_objects.abs > (@last_memory_state[:pages] / 3)
timediff = new_memory_state[:time] - @last_memory_state[:time]
warn "[MEMORY] #{new_memory_state[:time]} significant RAM Usage detected\n" \
"[MEMORY] #{new_memory_state[:time]} Pages : #{new_memory_state[:pages]}" \
" (diff #{diff_allocated} aka #{(diff_allocated / timediff).round(0)}/s) \n" \
"[MEMORY] #{new_memory_state[:time]} Objects: #{new_memory_state[:objects]}"\
" (diff #{diff_num_objects} aka #{(diff_num_objects / timediff).round(0)}/s)"
@last_memory_state = new_memory_state
end
end
end
end
@result
end
end
end
end