tengine_core 0.5.28

Sign up to get free protection for your applications and to get access to all the features.
Files changed (156) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +40 -0
  4. data/Gemfile.lock +95 -0
  5. data/README.md +54 -0
  6. data/Rakefile +44 -0
  7. data/VERSION +1 -0
  8. data/bin/tengine_atd +8 -0
  9. data/bin/tengine_heartbeat_watchd +8 -0
  10. data/bin/tengined +182 -0
  11. data/examples/VERSION +1 -0
  12. data/examples/uc01_execute_processing_for_event.rb +11 -0
  13. data/examples/uc02_fire_another_event.rb +16 -0
  14. data/examples/uc03_2handlers_for_1event.rb +16 -0
  15. data/examples/uc08_if_both_a_and_b_occurs.rb +11 -0
  16. data/examples/uc10_if_the_event_occurs_at_the_server.rb +15 -0
  17. data/examples/uc50_commit_event_at_first.rb +17 -0
  18. data/examples/uc51_commit_event_at_first_submit.rb +29 -0
  19. data/examples/uc52_commit_event_after_all_handler_submit.rb +31 -0
  20. data/examples/uc52_never_commit_event_unless_all_handler_submit.rb +31 -0
  21. data/examples/uc60_event_in_handler.rb +18 -0
  22. data/examples/uc62_session_in_driver.rb +16 -0
  23. data/examples/uc64_safety_countup.rb +14 -0
  24. data/examples/uc70_driver_enabled_on_activation.rb +13 -0
  25. data/examples/uc71_driver_disabled_on_activation.rb +14 -0
  26. data/examples/uc72_setup_eventmachine.rb +17 -0
  27. data/examples/uc80_raise_io_error.rb +10 -0
  28. data/examples/uc81_raise_runtime_error.rb +10 -0
  29. data/examples2/driver01.rb +18 -0
  30. data/examples2/driver02.rb +19 -0
  31. data/examples2/uc08_if_both_a_and_b_occurs.rb +13 -0
  32. data/examples2/uc10_if_the_event_occurs_at_the_server.rb +18 -0
  33. data/examples2/uc51_commit_event_at_first_submit_1.rb +16 -0
  34. data/examples2/uc51_commit_event_at_first_submit_2.rb +17 -0
  35. data/examples2/uc51_commit_event_at_first_submit_3.rb +17 -0
  36. data/examples2/uc62_session_in_driver.rb +16 -0
  37. data/examples2/uc71_driver_disabled_on_activation.rb +16 -0
  38. data/failure_examples/VERSION +1 -0
  39. data/failure_examples/uc53_submit_outside_of_handler.rb +15 -0
  40. data/failure_examples/uc61_event_outside_of_handler.rb +12 -0
  41. data/failure_examples/uc63_session_outside_of_driver.rb +13 -0
  42. data/lib/tengine/core.rb +74 -0
  43. data/lib/tengine/core/bootstrap.rb +123 -0
  44. data/lib/tengine/core/collection_accessible.rb +34 -0
  45. data/lib/tengine/core/config.rb +10 -0
  46. data/lib/tengine/core/config/atd.rb +225 -0
  47. data/lib/tengine/core/config/core.rb +319 -0
  48. data/lib/tengine/core/config/heartbeat_watcher.rb +229 -0
  49. data/lib/tengine/core/connection_test/.gitignore +1 -0
  50. data/lib/tengine/core/connection_test/fire_bar_on_foo.rb +16 -0
  51. data/lib/tengine/core/driveable.rb +213 -0
  52. data/lib/tengine/core/driver.rb +69 -0
  53. data/lib/tengine/core/driver/finder.rb +42 -0
  54. data/lib/tengine/core/dsl_evaluator.rb +110 -0
  55. data/lib/tengine/core/dsl_filter_def.rb +11 -0
  56. data/lib/tengine/core/dsl_loader.rb +108 -0
  57. data/lib/tengine/core/event.rb +145 -0
  58. data/lib/tengine/core/event/finder.rb +82 -0
  59. data/lib/tengine/core/event_exception_reportable.rb +88 -0
  60. data/lib/tengine/core/event_wrapper.rb +21 -0
  61. data/lib/tengine/core/find_by_name.rb +31 -0
  62. data/lib/tengine/core/handler.rb +152 -0
  63. data/lib/tengine/core/handler_path.rb +33 -0
  64. data/lib/tengine/core/heartbeat_watcher.rb +161 -0
  65. data/lib/tengine/core/io_to_logger.rb +22 -0
  66. data/lib/tengine/core/kernel.rb +510 -0
  67. data/lib/tengine/core/kernel_runtime.rb +91 -0
  68. data/lib/tengine/core/method_traceable.rb +38 -0
  69. data/lib/tengine/core/mongoid_fix.rb +19 -0
  70. data/lib/tengine/core/mutex.rb +177 -0
  71. data/lib/tengine/core/optimistic_lock.rb +69 -0
  72. data/lib/tengine/core/plugins.rb +54 -0
  73. data/lib/tengine/core/schedule.rb +21 -0
  74. data/lib/tengine/core/scheduler.rb +156 -0
  75. data/lib/tengine/core/selectable_attr.rb +29 -0
  76. data/lib/tengine/core/session.rb +21 -0
  77. data/lib/tengine/core/session_wrapper.rb +68 -0
  78. data/lib/tengine/core/setting.rb +21 -0
  79. data/lib/tengine/core/validation.rb +36 -0
  80. data/lib/tengine/errors.rb +18 -0
  81. data/lib/tengine/rspec.rb +8 -0
  82. data/lib/tengine/rspec/context_wrapper.rb +51 -0
  83. data/lib/tengine/rspec/extension.rb +53 -0
  84. data/lib/tengine_core.rb +23 -0
  85. data/spec/factories/tengine_core_drivers.rb +10 -0
  86. data/spec/factories/tengine_core_events.rb +14 -0
  87. data/spec/factories/tengine_core_handler_paths.rb +9 -0
  88. data/spec/factories/tengine_core_handlers.rb +9 -0
  89. data/spec/factories/tengine_core_sessions.rb +9 -0
  90. data/spec/mongoid.yml +35 -0
  91. data/spec/spec_helper.rb +48 -0
  92. data/spec/support/mongo_index_key_log.rb +91 -0
  93. data/spec/tengine/core/bootstrap_spec.rb +278 -0
  94. data/spec/tengine/core/bugfix/bind_dsl_file_in_multi_byte_dir_spec.rb +21 -0
  95. data/spec/tengine/core/bugfix/enabled_on_activation_spec.rb +112 -0
  96. data/spec/tengine/core/bugfix/receive_event_spec.rb +133 -0
  97. data/spec/tengine/core/bugfix/use_dsl_version_method.rb +12 -0
  98. data/spec/tengine/core/bugfix/use_dsl_version_method_spec.rb +28 -0
  99. data/spec/tengine/core/bugfix/use_event_in_handler_dsl.rb +11 -0
  100. data/spec/tengine/core/bugfix//351/235/236ACSII/343/201/256/343/203/206/343/202/231/343/202/243/343/203/254/343/202/257/343/203/210/343/203/252/345/220/215/source_location_encoding.rb +35 -0
  101. data/spec/tengine/core/bugfix//351/235/236ACSII/343/201/256/343/203/206/343/202/231/343/202/243/343/203/254/343/202/257/343/203/210/343/203/252/345/220/215//351/235/236ASCII/343/201/256/343/203/225/343/202/241/343/202/244/343/203/253/345/220/215_dsl.rb +38 -0
  102. data/spec/tengine/core/bugfix//351/235/236ACSII/343/201/256/343/203/207/343/202/243/343/203/254/343/202/257/343/203/210/343/203/252/345/220/215/source_location_encoding.rb +35 -0
  103. data/spec/tengine/core/bugfix//351/235/236ACSII/343/201/256/343/203/207/343/202/243/343/203/254/343/202/257/343/203/210/343/203/252/345/220/215//351/235/236ASCII/343/201/256/343/203/225/343/202/241/343/202/244/343/203/253/345/220/215_dsl.rb +38 -0
  104. data/spec/tengine/core/config/atd_spec.rb +62 -0
  105. data/spec/tengine/core/config/core_spec.rb +479 -0
  106. data/spec/tengine/core/config/heartbeat_watcher_spec.rb +62 -0
  107. data/spec/tengine/core/config/syntax_error_in_erb.yml.erb +13 -0
  108. data/spec/tengine/core/config/wrong_category_name.yml.erb +13 -0
  109. data/spec/tengine/core/config/wrong_field_name.yml.erb +12 -0
  110. data/spec/tengine/core/config/wrong_yaml.yml.erb +13 -0
  111. data/spec/tengine/core/config_spec/another_port.yml +54 -0
  112. data/spec/tengine/core/config_spec/config_with_dir_absolute_load_path.yml +16 -0
  113. data/spec/tengine/core/config_spec/config_with_dir_relative_load_path.yml +16 -0
  114. data/spec/tengine/core/config_spec/config_with_file_absolute_load_path.yml +16 -0
  115. data/spec/tengine/core/config_spec/config_with_file_relative_load_path.yml +16 -0
  116. data/spec/tengine/core/config_spec/log_config_spec.rb +235 -0
  117. data/spec/tengine/core/driveable_spec.rb +240 -0
  118. data/spec/tengine/core/driver_spec.rb +159 -0
  119. data/spec/tengine/core/dsl_loader_spec.rb +172 -0
  120. data/spec/tengine/core/dsls/uc08_if_both_a_and_b_occurs_spec.rb +35 -0
  121. data/spec/tengine/core/dsls/uc10_if_the_event_occurs_at_the_server_spec.rb +58 -0
  122. data/spec/tengine/core/dsls/uc50_commit_event_at_first_spec.rb +29 -0
  123. data/spec/tengine/core/dsls/uc52_commit_event_after_all_handler_submit_spec.rb +33 -0
  124. data/spec/tengine/core/dsls/uc52_never_commit_event_unless_all_handler_submit_spec.rb +37 -0
  125. data/spec/tengine/core/dsls/uc53_submit_outside_of_handler_spec.rb +37 -0
  126. data/spec/tengine/core/dsls/uc60_event_in_handler_spec.rb +31 -0
  127. data/spec/tengine/core/dsls/uc61_event_outside_of_handler_spec.rb +37 -0
  128. data/spec/tengine/core/dsls/uc62_session_in_driver_spec.rb +36 -0
  129. data/spec/tengine/core/dsls/uc63_session_outside_of_driver_spec.rb +35 -0
  130. data/spec/tengine/core/dsls/uc64_safety_countup_spec.rb +134 -0
  131. data/spec/tengine/core/dsls/uc70_driver_enabled_on_activation_spec.rb +39 -0
  132. data/spec/tengine/core/dsls/uc71_driver_disabled_on_activation_spec.rb +36 -0
  133. data/spec/tengine/core/dsls/uc72_setup_eventmachine_spec.rb +39 -0
  134. data/spec/tengine/core/dsls/uc80_raise_io_error_spec.rb +53 -0
  135. data/spec/tengine/core/dsls/uc81_raise_runtime_error_spec.rb +49 -0
  136. data/spec/tengine/core/event/finder_spec.rb +136 -0
  137. data/spec/tengine/core/event_exception_reportable_spec.rb +33 -0
  138. data/spec/tengine/core/event_spec.rb +161 -0
  139. data/spec/tengine/core/event_wrapper_spec.rb +35 -0
  140. data/spec/tengine/core/handler_path_spec.rb +87 -0
  141. data/spec/tengine/core/handler_spec.rb +190 -0
  142. data/spec/tengine/core/heartbeat_watcher_spec.rb +131 -0
  143. data/spec/tengine/core/io_to_logger_spec.rb +30 -0
  144. data/spec/tengine/core/kernel_spec.rb +885 -0
  145. data/spec/tengine/core/mutex_spec.rb +184 -0
  146. data/spec/tengine/core/optimistic_lock_spec.rb +55 -0
  147. data/spec/tengine/core/scheculer_spec.rb +121 -0
  148. data/spec/tengine/core/selectable_attr_spec.rb +30 -0
  149. data/spec/tengine/core/session_spec.rb +104 -0
  150. data/spec/tengine/core/setting_spec.rb +79 -0
  151. data/spec/tengine/core_spec.rb +13 -0
  152. data/spec/tengine_spec.rb +14 -0
  153. data/tengine_core.gemspec +248 -0
  154. data/tmp/log/.gitignore +1 -0
  155. data/tmp/tengined_status/.gitignore +1 -0
  156. metadata +421 -0
@@ -0,0 +1,319 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'tengine/core/config'
3
+
4
+ require 'yaml'
5
+ require 'optparse'
6
+ require 'active_support/memoizable'
7
+ require 'active_support/core_ext/class/attribute_accessors'
8
+
9
+ require 'tengine/support/yaml_with_erb'
10
+
11
+ Tengine::Support::Config::Definition::Group.module_eval do
12
+ def symbolize_keys
13
+ to_hash
14
+ end
15
+ end
16
+
17
+ class Tengine::Core::Config::Core < Tengine::Support::Config::Definition::Suite
18
+ # memoize については http://wota.jp/ac/?date=20081025#p11 などを参照してください
19
+ extend ActiveSupport::Memoizable
20
+
21
+ class << self
22
+ # この辺は以前のTengine::Core::Configとの互換のために用意してあります
23
+ def [](hash_or_suite)
24
+ case hash_or_suite
25
+ when Tengine::Core::Config::Core then hash_or_suite
26
+ when Hash then
27
+ result = Tengine::Core::Config::Core.new
28
+ result.load(hash_or_suite)
29
+ result
30
+ else
31
+ raise "unsupported class: #{hash_or_suite.class.inspect}"
32
+ end
33
+ end
34
+
35
+ def default_hash
36
+ new.to_hash
37
+ end
38
+ alias_method :skelton_hash, :default_hash
39
+
40
+ def parse_to_hash(args)
41
+ config = new
42
+ config.parse!(args)
43
+ result = new
44
+ result.config = config.config
45
+ result.to_hash
46
+ end
47
+
48
+ def parse(args)
49
+ config = new
50
+ config.parse!(args)
51
+ config
52
+ end
53
+
54
+ end
55
+
56
+ def initialize(hash_or_filepath = nil)
57
+ build if respond_to?(:build)
58
+ case hash_or_filepath
59
+ when Hash then
60
+ if config = hash_or_filepath[:config]
61
+ load_file(config)
62
+ else
63
+ load(hash_or_filepath)
64
+ end
65
+ when String then load_file(hash_or_filepath)
66
+ end
67
+ end
68
+
69
+ def load_file(filepath)
70
+ super
71
+ rescue Exception => e
72
+ msg = e.message
73
+ unless msg.include?(filepath)
74
+ msg = "#{msg} in #{filepath}"
75
+ end
76
+ raise Tengine::Core::ConfigError, msg
77
+ end
78
+
79
+
80
+ def build
81
+ banner <<EOS
82
+ Usage: tengined [-k action] [-f path_to_config] [-T path/to/file_or_dir]
83
+ [-o mq_conn_host] [-p mq_conn_port] [-u mq_conn_user]
84
+ [-s mq_conn_pass] [-e mq_exchange_name] [-q mq_queue_name]
85
+ EOS
86
+
87
+ field(:action, "test|load|start|enable|stop|force-stop|status|activate", :type => :string, :default => "start")
88
+ load_config(:config, "path/to/config_file", :type => :string)
89
+
90
+ add(:process, Tengine::Core::Config::Core::Process)
91
+ add(:tengined, Tengine::Core::Config::Core::Tengined)
92
+ field(:db, "settings to connect to db", :type => :hash, :default => {
93
+ 'host' => 'localhost',
94
+ 'port' => 27017,
95
+ 'username' => nil,
96
+ 'password' => nil,
97
+ 'database' => 'tengine_production',
98
+ })
99
+
100
+ group(:event_queue, :hidden => true) do
101
+ add(:connection, AmqpConnection)
102
+ add(:exchange , Tengine::Support::Config::Amqp::Exchange, :defaults => {:name => 'tengine_event_exchange'})
103
+ add(:queue , Tengine::Support::Config::Amqp::Queue , :defaults => {:name => 'tengine_event_queue'})
104
+ end
105
+
106
+ add(:log_common, Tengine::Support::Config::Logger,
107
+ :defaults => {
108
+ :rotation => 3 ,
109
+ :rotation_size => 1024 * 1024,
110
+ :level => 'info' ,
111
+ })
112
+ add(:application_log, Tengine::Core::Config::Core::LoggerConfig,
113
+ :parameters => {:logger_name => "application"},
114
+ :dependencies => { :process_config => :process, :log_common => :log_common,}){
115
+ self.formatter = lambda{|level, t, prog, msg| "#{t.iso8601} #{level} #{@process_identifier} #{msg}\n"}
116
+ }
117
+ add(:process_stdout_log, Tengine::Core::Config::Core::LoggerConfig,
118
+ :parameters => {:logger_name => "#{File.basename($PROGRAM_NAME)}_#{::Process.pid}_stdout"},
119
+ :dependencies => { :process_config => :process, :log_common => :log_common,}){
120
+ self.formatter = lambda{|level, t, prog, msg| "#{t.iso8601} STDOUT #{@process_identifier} #{msg}\n"}
121
+ }
122
+ add(:process_stderr_log, Tengine::Core::Config::Core::LoggerConfig,
123
+ :parameters => {:logger_name => "#{File.basename($PROGRAM_NAME)}_#{::Process.pid}_stderr"},
124
+ :dependencies => { :process_config => :process, :log_common => :log_common,},
125
+ :defaults => {
126
+ :output => proc{ process_config.daemon ? "./log/#{logger_name}.log" : "STDERR" }}){
127
+ self.formatter = lambda{|level, t, prog, msg| "#{t.iso8601} STDERR #{@process_identifier} #{msg}\n"}
128
+ }
129
+
130
+ group(:heartbeat) do
131
+ add(:core , Tengine::Core::Config::Core::Heartbeat)
132
+ # add(:job , Tengine::Core::Config::Core::Heartbeat, :defaults => {:interval => 5, :expire => 20})
133
+ # add(:hbw , Tengine::Core::Config::Core::Heartbeat)
134
+ # add(:resourcew, Tengine::Core::Config::Core::Heartbeat)
135
+ # add(:atd , Tengine::Core::Config::Core::Heartbeat)
136
+ end
137
+
138
+ separator("\nGeneral:")
139
+ field(:verbose, "Show detail to this command", :type => :boolean)
140
+ __action__(:version, "show version"){ STDOUT.puts Tengine::Core.version.to_s; exit }
141
+ __action__(:dump_skelton, "dump skelton of config"){ STDOUT.puts YAML.dump(root.to_hash); exit }
142
+ __action__(:help , "show this help message"){ STDOUT.puts option_parser.help; exit }
143
+
144
+ mapping({
145
+ [:action] => :k,
146
+ [:config] => :f,
147
+ [:tengined, :daemon] => :D,
148
+ [:tengined, :load_path] => :T,
149
+ # [:tengined, :heartbeat_period] => :G,
150
+ [:tengined, :confirmation_threshold] => :C,
151
+
152
+ [:event_queue, :connection, :host] => :o,
153
+ [:event_queue, :connection, :port] => :p,
154
+ [:event_queue, :connection, :user] => :u,
155
+ [:event_queue, :connection, :pass] => :s,
156
+ [:event_queue, :exchange , :name] => :e,
157
+ [:event_queue, :queue , :name] => :q,
158
+
159
+ [:heartbeat, :core, :interval] => :G,
160
+
161
+ [:verbose] => :V,
162
+ [:version] => :v,
163
+ [:help] => :h
164
+ })
165
+ end
166
+
167
+ class Process
168
+ include Tengine::Support::Config::Definition
169
+
170
+ field :daemon, "process works on background.", :type => :boolean, :default => false
171
+ field :pid_dir, "path/to/dir for PID created.", :type => :directory, :default => "./tmp/tengined_pids"
172
+ end
173
+
174
+ class Tengined
175
+ include Tengine::Support::Config::Definition
176
+
177
+ cattr_accessor :default_cache_drivers
178
+
179
+ field :load_path , "[REQUIRED] path/to/file_or_dir. ignored with \"-k test\".", :type => :string
180
+ field :cache_drivers , "if set this, tengine doesn't reload driver.", :type => :boolean,
181
+ :default => proc{ Tengine::Core::Config::Core::Tengined.default_cache_drivers} # spec/spec_helper.rb でtrueに設定しています。
182
+ field :skip_load , "doesn't load event handler when start. usually use with --daemon option. [only for command]", :type => :boolean
183
+ field :skip_enablement , "doesn't enable event handler when start. usually use with --daemon option. [only for command]", :type => :boolean
184
+ field :wait_activation , "wait activation when start. usually use with --daemon option [only for command]", :type => :boolean
185
+ field :activation_timeout , "period to wait for making activation file.", :type => :integer, :default => 300
186
+ field :status_dir , "path/to/dir.", :type => :directory, :default => "./tmp/tengined_status"
187
+ field :activation_dir , "path/to/dir.", :type => :directory, :default => "./tmp/tengined_activations"
188
+ # field :heartbeat_period , "the second of period which heartbeat event be fired. disable heartbeat if 0.", :type => :integer, :default => 0
189
+ field :confirmation_threshold, "the event which is this level or less will be made confirmed automatically. debug/info/warn/error/fatal. ", :type => :string, :default => 'info'
190
+ end
191
+
192
+ class AmqpConnection < Tengine::Support::Config::Amqp::Connection
193
+ field :vhost, :default => '/'
194
+ field :user , :default => 'guest'
195
+ field :pass , :default => 'guest'
196
+ field :logging, :type => :boolean, :default => false
197
+ field :insist, :type => :boolean, :default => false
198
+ field :auto_reconnect_delay, :type => :integer, :default => 1
199
+ end
200
+
201
+ class LoggerConfig < Tengine::Support::Config::Logger
202
+ parameter :logger_name
203
+ depends :process_config
204
+ depends :log_common
205
+ field :output,
206
+ :default => proc{
207
+ process_config.daemon ?
208
+ "./log/#{logger_name}.log" : "STDOUT" },
209
+ :default_description => proc{"if daemon process then \"./log/#{logger_name}.log\" else \"STDOUT\""}
210
+ field :rotation,
211
+ :default => proc{ log_common.rotation },
212
+ :default_description => proc{"value of #{log_common.long_opt}-rotation"}
213
+ field :rotation_size,
214
+ :default => proc{ log_common.rotation_size },
215
+ :default_description => proc{"value of #{log_common.long_opt}-rotation-size"}
216
+ field :level,
217
+ :default => proc{ log_common.level },
218
+ :default_description => proc{"value of #{log_common.long_opt}-level"}
219
+
220
+ def new_logger *;
221
+ super.tap {|i| i.formatter = self.formatter }
222
+ end
223
+ end
224
+
225
+ class Heartbeat
226
+ include Tengine::Support::Config::Definition
227
+ field :interval, "heartbeat interval seconds. usually about 30 seconds", :type => :integer, :default => 0
228
+ field :expire , "heartbeat expire seconds" , :type => :integer, :default => 120
229
+ end
230
+
231
+ def dsl_load_path
232
+ original = self[:tengined][:load_path]
233
+ # 本来は指定する必要はありませんが、specでDir.pwdをstubで返すようにするために、明示的に第2引数にDir.pwdを指定しています
234
+ original ? File.expand_path(original, Dir.pwd) : nil
235
+ end
236
+ memoize :dsl_load_path
237
+
238
+ def prepare_dir_and_paths(force = false)
239
+ return if !force && @prepare_dir_and_paths_done
240
+ path = dsl_load_path(true) # キャッシュをクリア
241
+ if path.nil?
242
+ @dsl_dir_path = nil
243
+ @dsl_file_paths = []
244
+ elsif Dir.exist?(path)
245
+ @dsl_dir_path = File.expand_path(path)
246
+ @dsl_file_paths = Dir.glob("#{@dsl_dir_path}/**/*.rb")
247
+ elsif File.exist?(path)
248
+ @dsl_dir_path = File.expand_path(File.dirname(path))
249
+ @dsl_dir_path.force_encoding(@dsl_dir_path.encoding)
250
+ @dsl_file_paths = [dsl_load_path]
251
+ else
252
+ raise Tengine::Core::ConfigError, "file or directory doesn't exist. #{path}"
253
+ end
254
+ @prepare_dir_and_paths_done = true
255
+ end
256
+
257
+ def dsl_dir_path
258
+ prepare_dir_and_paths
259
+ @dsl_dir_path
260
+ end
261
+
262
+ def dsl_file_paths
263
+ prepare_dir_and_paths
264
+ @dsl_file_paths
265
+ end
266
+
267
+ def dsl_version_path
268
+ path = dsl_dir_path
269
+ path ? File.expand_path("VERSION", path) : nil
270
+ end
271
+ memoize :dsl_version_path
272
+
273
+ def dsl_version
274
+ path = dsl_version_path
275
+ (path && File.exist?(dsl_version_path)) ? File.read(dsl_version_path).strip : Time.now.strftime("%Y%m%d%H%M%S")
276
+ end
277
+ memoize :dsl_version
278
+
279
+ def relative_path_from_dsl_dir(filepath)
280
+ path = Pathname.new(filepath)
281
+ path.relative? ? path.to_s : path.relative_path_from(Pathname.new(dsl_dir_path)).to_s
282
+ end
283
+
284
+ def status_dir
285
+ self[:tengined][:status_dir]
286
+ end
287
+ memoize :status_dir
288
+
289
+ def activation_dir
290
+ self[:tengined][:activation_dir]
291
+ end
292
+ memoize :activation_dir
293
+
294
+ def confirmation_threshold
295
+ Tengine::Event::LEVELS_INV[ self[:tengined][:confirmation_threshold].to_sym ]
296
+ end
297
+ memoize :confirmation_threshold
298
+
299
+ def heartbeat_period
300
+ # [:][:heartbeat_period].to_i
301
+ heartbeat.core.interval.to_i
302
+ end
303
+
304
+ def heartbeat_enabled?
305
+ heartbeat_period > 0
306
+ end
307
+
308
+ def setup_loggers
309
+ Tengine.logger = application_log.new_logger
310
+ Tengine::Core.stdout_logger = process_stdout_log.new_logger
311
+ Tengine::Core.stderr_logger = process_stderr_log.new_logger
312
+
313
+ Tengine::Core.stdout_logger.info("#{self.class.name}#setup_loggers complete")
314
+ rescue Exception
315
+ Tengine::Core.stderr_logger.info("#{self.class.name}#setup_loggers failure")
316
+ raise
317
+ end
318
+
319
+ end
@@ -0,0 +1,229 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'tengine/core/config'
3
+
4
+ require 'yaml'
5
+ require 'optparse'
6
+ require 'active_support/memoizable'
7
+
8
+ require 'tengine/support/yaml_with_erb'
9
+
10
+ Tengine::Support::Config::Definition::Group.module_eval do
11
+ def symbolize_keys
12
+ to_hash
13
+ end
14
+ end
15
+
16
+ class Tengine::Core::Config::HeartbeatWatcher < Tengine::Support::Config::Definition::Suite
17
+ # memoize については http://wota.jp/ac/?date=20081025#p11 などを参照してください
18
+ extend ActiveSupport::Memoizable
19
+
20
+ class << self
21
+ # この辺は以前のTengine::Core::Configとの互換のために用意してあります
22
+ def [](hash_or_suite)
23
+ case hash_or_suite
24
+ when Tengine::Core::Config::HeartbeatWatcher then hash_or_suite
25
+ when Hash then
26
+ result = Tengine::Core::Config::HeartbeatWatcher.new
27
+ result.load(hash_or_suite)
28
+ result
29
+ else
30
+ raise "unsupported class: #{hash_or_suite.class.inspect}"
31
+ end
32
+ end
33
+
34
+ def default_hash
35
+ new.to_hash
36
+ end
37
+ alias_method :skelton_hash, :default_hash
38
+
39
+ def parse_to_hash(args)
40
+ config = new
41
+ config.parse!(args)
42
+ result = new
43
+ result.config = config.config
44
+ result.to_hash
45
+ end
46
+
47
+ def parse(args)
48
+ config = new
49
+ config.parse!(args)
50
+ config
51
+ end
52
+
53
+ end
54
+
55
+ def initialize(hash_or_filepath = nil)
56
+ build if respond_to?(:build)
57
+ case hash_or_filepath
58
+ when Hash then
59
+ if config = hash_or_filepath[:config]
60
+ load_file(config)
61
+ else
62
+ load(hash_or_filepath)
63
+ end
64
+ when String then load_file(hash_or_filepath)
65
+ end
66
+ end
67
+
68
+ def load_file(filepath)
69
+ super
70
+ rescue Exception => e
71
+ msg = e.message
72
+ unless msg.include?(filepath)
73
+ msg = "#{msg} in #{filepath}"
74
+ end
75
+ raise Tengine::Core::ConfigError, msg
76
+ end
77
+
78
+
79
+ def build
80
+ banner <<EOS
81
+ Usage: tengine_heartbeat_watchd [-k action] [-f path_to_config] [-D process_daemon]
82
+ [-o mq_conn_host] [-p mq_conn_port] [-u mq_conn_user]
83
+ [-s mq_conn_pass] [-e mq_exchange_name] [-q mq_queue_name]
84
+ [-G heartbeat_hbw_interval]
85
+ EOS
86
+
87
+ field(:action, "start|stop", :type => :string, :default => "start")
88
+ load_config(:config, "path/to/config_file", :type => :string)
89
+
90
+ add(:process, Tengine::Core::Config::HeartbeatWatcher::Process)
91
+ field(:db, "settings to connect to db", :type => :hash, :default => {
92
+ 'host' => 'localhost',
93
+ 'port' => 27017,
94
+ 'username' => nil,
95
+ 'password' => nil,
96
+ 'database' => 'tengine_production',
97
+ })
98
+
99
+ group(:heartbeat) do
100
+ add(:core , Tengine::Core::Config::Core::Heartbeat)
101
+ add(:job , Tengine::Core::Config::Core::Heartbeat, :defaults => {:interval => 5, :expire => 20})
102
+ add(:hbw , Tengine::Core::Config::Core::Heartbeat)
103
+ add(:resourcew, Tengine::Core::Config::Core::Heartbeat)
104
+ add(:atd , Tengine::Core::Config::Core::Heartbeat)
105
+ end
106
+
107
+ group(:event_queue, :hidden => true) do
108
+ add(:connection, AmqpConnection)
109
+ add(:exchange , Tengine::Support::Config::Amqp::Exchange, :defaults => {:name => 'tengine_event_exchange'})
110
+ add(:queue , Tengine::Support::Config::Amqp::Queue , :defaults => {:name => 'tengine_event_queue'})
111
+ end
112
+
113
+ add(:log_common, Tengine::Support::Config::Logger,
114
+ :defaults => {
115
+ :rotation => 3 ,
116
+ :rotation_size => 1024 * 1024,
117
+ :level => 'info' ,
118
+ })
119
+ add(:application_log, Tengine::Core::Config::HeartbeatWatcher::LoggerConfig,
120
+ :parameters => {:logger_name => "application"},
121
+ :dependencies => { :process_config => :process, :log_common => :log_common,}){
122
+ self.formatter = lambda{|level, t, prog, msg| "#{t.iso8601} #{level} #{@process_identifier} #{msg}\n"}
123
+ }
124
+ add(:process_stdout_log, Tengine::Core::Config::HeartbeatWatcher::LoggerConfig,
125
+ :parameters => {:logger_name => "#{File.basename($PROGRAM_NAME)}_#{::Process.pid}_stdout"},
126
+ :dependencies => { :process_config => :process, :log_common => :log_common,}){
127
+ self.formatter = lambda{|level, t, prog, msg| "#{t.iso8601} STDOUT #{@process_identifier} #{msg}\n"}
128
+ }
129
+ add(:process_stderr_log, Tengine::Core::Config::HeartbeatWatcher::LoggerConfig,
130
+ :parameters => {:logger_name => "#{File.basename($PROGRAM_NAME)}_#{::Process.pid}_stderr"},
131
+ :dependencies => { :process_config => :process, :log_common => :log_common,},
132
+ :defaults => {
133
+ :output => proc{ process_config.daemon ? "./log/#{logger_name}.log" : "STDERR" }}){
134
+ self.formatter = lambda{|level, t, prog, msg| "#{t.iso8601} STDERR #{@process_identifier} #{msg}\n"}
135
+ }
136
+
137
+ separator("\nGeneral:")
138
+ field(:verbose, "Show detail to this command", :type => :boolean)
139
+ __action__(:version, "show version"){ STDOUT.puts Tengine::Core.version.to_s; exit }
140
+ __action__(:dump_skelton, "dump skelton of config"){ STDOUT.puts YAML.dump(root.to_hash); exit }
141
+ __action__(:help , "show this help message"){ STDOUT.puts option_parser.help; exit }
142
+
143
+ mapping({
144
+ [:action] => :k,
145
+ [:config] => :f,
146
+ [:process, :daemon] => :D,
147
+
148
+ [:event_queue, :connection, :host] => :o,
149
+ [:event_queue, :connection, :port] => :p,
150
+ [:event_queue, :connection, :user] => :u,
151
+ [:event_queue, :connection, :pass] => :s,
152
+ [:event_queue, :exchange , :name] => :e,
153
+ [:event_queue, :queue , :name] => :q,
154
+
155
+ [:heartbeat, :hbw, :interval] => :G,
156
+
157
+ [:verbose] => :V,
158
+ [:version] => :v,
159
+ [:help] => :h
160
+ })
161
+ end
162
+
163
+ class Process
164
+ include Tengine::Support::Config::Definition
165
+
166
+ field :daemon, "process works on background.", :type => :boolean, :default => false
167
+ field :pid_dir, "path/to/dir for PID created.", :type => :directory, :default => "./pids"
168
+ end
169
+
170
+ def heartbeat_period
171
+ # [:][:heartbeat_period].to_i
172
+ heartbeat.interval.to_i
173
+ end
174
+
175
+ def heartbeat_enabled?
176
+ heartbeat_period > 0
177
+ end
178
+
179
+ class AmqpConnection < Tengine::Support::Config::Amqp::Connection
180
+ field :vhost, :default => '/'
181
+ field :user , :default => 'guest'
182
+ field :pass , :default => 'guest'
183
+ field :logging, :type => :boolean, :default => false
184
+ field :insist, :type => :boolean, :default => false
185
+ field :auto_reconnect_delay, :type => :integer, :default => 1
186
+ end
187
+
188
+ class LoggerConfig < Tengine::Support::Config::Logger
189
+ parameter :logger_name
190
+ depends :process_config
191
+ depends :log_common
192
+ field :output, {
193
+ :default => proc {
194
+ process_config.daemon ? "./log/#{logger_name}.log" : "STDOUT"
195
+ },
196
+ :default_description => proc {
197
+ "if daemon process then \"./log/#{logger_name}.log\" else \"STDOUT\""
198
+ }
199
+ }
200
+ field :rotation, {
201
+ :default => proc{ log_common.rotation },
202
+ :default_description => proc{ "value of #{log_common.long_opt}-rotation" }
203
+ }
204
+ field :rotation_size, {
205
+ :default => proc{ log_common.rotation_size },
206
+ :default_description => proc{ "value of #{log_common.long_opt}-rotation-size" }
207
+ }
208
+ field :level, {
209
+ :default => proc{ log_common.level },
210
+ :default_description => proc{ "value of #{log_common.long_opt}-level" }
211
+ }
212
+
213
+ def new_logger *;
214
+ super.tap {|i| i.formatter = self.formatter }
215
+ end
216
+ end
217
+
218
+ def setup_loggers
219
+ Tengine.logger = application_log.new_logger
220
+ Tengine::Core.stdout_logger = process_stdout_log.new_logger
221
+ Tengine::Core.stderr_logger = process_stderr_log.new_logger
222
+
223
+ Tengine::Core.stdout_logger.info("#{self.class.name}#setup_loggers complete")
224
+ rescue Exception
225
+ Tengine::Core.stderr_logger.info("#{self.class.name}#setup_loggers failure")
226
+ raise
227
+ end
228
+
229
+ end