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,11 @@
1
+ require 'tengine/core'
2
+
3
+ class Tengine::Core::DslFilterDef
4
+ attr_reader :filter
5
+ attr_reader :event_type_names
6
+ def initialize(event_type_names, filter)
7
+ @event_type_names = event_type_names
8
+ @filter = filter
9
+ end
10
+
11
+ end
@@ -0,0 +1,108 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'pathname'
3
+
4
+ module Tengine::Core::DslLoader
5
+ include Tengine::Core::DslEvaluator
6
+
7
+ attr_accessor :__kernel__
8
+
9
+
10
+ # どのようなポリシーでackを返すのかをイベント種別名毎に指定できます。
11
+ #
12
+ # @param [Symbol] policy ackポリシー
13
+ # @param [[Symbol/String]] args イベント種別名の配列
14
+ #
15
+ # 例:
16
+ # {include:file:examples/uc50_commit_event_at_first.rb}
17
+ #
18
+ # 例:
19
+ # {include:file:examples/uc51_commit_event_at_first_submit.rb}
20
+ #
21
+ # 例:
22
+ # {include:file:examples/uc52_commit_event_after_all_handler_submit.rb}
23
+ #
24
+ def ack_policy(policy, *args)
25
+ args.each{|arg| @__kernel__.add_ack_policy(arg, policy)}
26
+ end
27
+
28
+ # このメソッドにブロックを渡すことで、Tengineコアが使用するEventMachineの初期化を行うために設定を行うことができます。
29
+ #
30
+ # 例:
31
+ # {include:file:examples/uc72_setup_eventmachine.rb}
32
+ #
33
+ def setup_eventmachine(&block)
34
+ return unless block
35
+ @__kernel__.em_setup_blocks << block
36
+ end
37
+
38
+ # イベントドライバを登録します。
39
+ #
40
+ # イベントドライバはonメソッドで定義されるイベントハンドラを持つことができます。
41
+ # イベントドライバは実行時のユーザーによる有効化、無効化の対象になります。
42
+ # 無効化されたイベントドライバのイベントハンドラは、イベントが発生した際に
43
+ # それがフィルタにマッチしたとしても、その処理を実行しません。
44
+ # つまりイベントハンドラの有効化、無効化は、それをまとめているイベントドライバ毎に
45
+ # 指定することが可能です。
46
+ #
47
+ # @param [String] name イベントドライバ名
48
+ # @param [Hash] options オプション
49
+ # @option options [String] :enabled_on_activation 実行時に有効にするならばtrue、でなければfalse。デフォルトはtrue
50
+ # @return [Tengine::Core::Driver]
51
+ # @see #on
52
+ #
53
+ # 例:
54
+ # {include:file:examples/uc01_execute_processing_for_event.rb}
55
+ def driver(name, options = {}, &block)
56
+ unless block_given?
57
+ # Tengine::Core::stdout.info("no block given at #{caller.first}")
58
+ return
59
+ end
60
+
61
+ if dsl_version_document = Tengine::Core::Setting.first(:conditions => {:name => "dsl_version"})
62
+ dsl_version_document.value = config.dsl_version
63
+ dsl_version_document.save!
64
+ else
65
+ Tengine::Core::Setting.create!(:name => "dsl_version", :value => config.dsl_version)
66
+ end
67
+ c = config
68
+ klass = Class.new
69
+ const_name = name.to_s.camelize
70
+ # if Object.constants.include?(const_name) || defined?(const_name)
71
+ # puts "#{const_name} is already defined\n " << caller.join("\n ")
72
+ # end
73
+ Object.send :remove_const, const_name if Object.const_defined? const_name
74
+ Object.const_set(const_name, klass)
75
+ klass.module_eval do
76
+ include Tengine::Core::Driveable::ByDsl
77
+ self.singleton_class.config = c
78
+ self.singleton_class.options = options
79
+ include Tengine::Core::Driveable
80
+ end
81
+ begin
82
+ klass.module_eval(&block)
83
+ rescue Exception => e
84
+ driver = klass.driver
85
+ driver.destroy if driver && !driver.new_record?
86
+ raise e
87
+ end
88
+ end
89
+
90
+ # @see Tengine::Core::DslBinder#session
91
+ def session
92
+ raise Tengine::Core::DslError, "session is not available outside of event driver block." unless @__session__
93
+ @__session_wrapper__ ||= Tengine::Core::SessionWrapper.new(@__session__)
94
+ end
95
+
96
+ def fire(*args, &blcok)
97
+ options = args.extract_options!
98
+ options[:keep_connection] = true
99
+ args = args + [options]
100
+ Tengine::Event.fire(*args, &blcok)
101
+ end
102
+
103
+ # 現時点ではMM1との互換性のためのダミーのメソッドです
104
+ # 必要があれば将来ちゃんと役割を見直して復活するかもしれません
105
+ def dsl_version(*args)
106
+ end
107
+
108
+ end
@@ -0,0 +1,145 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'tengine/core'
3
+
4
+ require 'selectable_attr'
5
+
6
+ class Tengine::Core::Event
7
+ autoload :Finder, 'tengine/core/event/finder'
8
+
9
+ include Mongoid::Document
10
+ include Mongoid::Timestamps
11
+ include Tengine::Core::Validation
12
+ include Tengine::Core::SelectableAttr
13
+ include Tengine::Core::CollectionAccessible
14
+
15
+ field :lock_version , :type => Integer, :default => -(2**63)
16
+ field :event_type_name, :type => String
17
+ field :key , :type => String
18
+ field :source_name , :type => String
19
+ field :occurred_at , :type => Time
20
+ field :level , :type => Integer, :default => 2
21
+ field :confirmed , :type => Boolean
22
+ field :sender_name , :type => String
23
+ field :properties , :type => Hash
24
+ map_yaml_accessor :properties
25
+
26
+ validates :event_type_name, :presence => true, :format => EVENT_TYPE_NAME.options
27
+
28
+ # 以下の2つはバリデーションを設定したいところですが、外部からの入力は極力保存できる
29
+ # ようにしたいのでバリデーションを外します。
30
+ # validates :source_name, :presence => true #, :format => RESOURCE_IDENTIFIER.options
31
+ # validates :sender_name, :presence => true #, :format => RESOURCE_IDENTIFIER.options
32
+
33
+ # 複数の経路から同じ意味のイベントが複数個送られる場合に
34
+ # これらを重複して登録しないようにユニーク制約を設定
35
+ index :key, unique: true
36
+ # :unique => trueのindexを設定しているので、uniquenessのバリデーションは設定しません
37
+ validates :key, :presence => true #, :uniqueness => true
38
+
39
+ index([ [:event_type_name, Mongo::ASCENDING], [:confirmed, Mongo::ASCENDING], ])
40
+ index([ [:event_type_name, Mongo::ASCENDING], [:level, Mongo::ASCENDING], [:occurred_at, Mongo::DESCENDING], ])
41
+ index([ [:event_type_name, Mongo::ASCENDING], [:occurred_at, Mongo::ASCENDING], ])
42
+ index([ [:event_type_name, Mongo::ASCENDING], [:source_name, Mongo::ASCENDING], ])
43
+ index([ [:level, Mongo::ASCENDING], [:sender_name, Mongo::ASCENDING], [:occurred_at, Mongo::DESCENDING], ])
44
+ index([ [:level, Mongo::ASCENDING], [:occurred_at, Mongo::DESCENDING], ])
45
+ index([ [:source_name, Mongo::ASCENDING], [:level, Mongo::ASCENDING], [:occurred_at, Mongo::DESCENDING], ])
46
+
47
+ # selectable_attrを使ってます
48
+ # see http://github.com/akm/selectable_attr
49
+ # http://github.com/akm/selectable_attr_rails
50
+ selectable_attr :level do
51
+ entry 1, :debug , "debug"
52
+ entry 2, :info , "info"
53
+ entry 3, :warn , "warn"
54
+ entry 4, :error , "error"
55
+ entry 5, :fatal , "fatal"
56
+ end
57
+
58
+ attr_accessor :kernel # tengined実行時に処理しているカーネルのインスタンスを保持します
59
+
60
+ def to_hash
61
+ ret = attributes.dup # <- dup ?
62
+ ret.delete "_id"
63
+ ret
64
+ end
65
+
66
+ # TODO: Tengine::Core::OptimisticLockを拡張して、ここでも使えるよう
67
+ # にする。現状は同じようなコードが複数箇所にあってよくない。
68
+
69
+ # @yield [event] Yields the (possibly new) event.
70
+ # @yieldparam [Tengine::Core::Event] event The event in question.
71
+ # @yieldreturn [Boolean] Return false, and it will just break the execution. Otherwise, it tries to update the event.
72
+ # @param [Hash] condition Criteria to find a document.
73
+ # @param [Numeric] retry_max (3) Maximum number of retry attempts to save the event.
74
+ # @return [Tengine::Core::Event] The event in question if update succeeded, false if retry_max reached, or nil if the block exited with false.
75
+ # @raise [Mongo::OperationFailure] Any exceptions that happened inside will be propagated outside.
76
+ def self.find_or_create_then_update_with_block condition, retry_max = 3
77
+ # * とある条件を満たすイベントがあれば、それを上書きしたい。
78
+ # * なければ、新規作成したい。
79
+ # * でもアトミックにやりたい。
80
+ # * ないとおもって新規作成しようとしたら裏でイベントが生えていたら、上書きモードでやり直したい。
81
+ # * あるとおもって上書きしようとしたら裏でイベントが消えていたら、新規作成モードでやり直したい。
82
+ # * という要求をできるだけ高速に処理したい。
83
+
84
+ the_event = nil
85
+ retries = -1
86
+ results = nil
87
+
88
+ case collection.driver.db.connection when Mongo::ReplSetConnection then
89
+ safemode = { :w => "majority", :wtimeout => 1024, } # mongodb 2.0+, 参加しているレプリカセットの多数派に書き込んだ時点でOK扱い
90
+ else
91
+ safemode = true
92
+ end
93
+
94
+ while true do
95
+ return false if retries >= retry_max # retryしすぎ
96
+
97
+ retries += 1
98
+ # あればとってくる
99
+ if the_event and not the_event.new_record?
100
+ the_event.reload
101
+ else
102
+ the_event = where(condition).first || new(condition)
103
+ end
104
+
105
+ return nil if not yield(the_event) # ユザーによる意図的な中断
106
+
107
+ hash = the_event.as_document.dup # <- dup ?
108
+ hash.delete "_id"
109
+ hash['lock_version'] = the_event.lock_version + 1
110
+ hash['created_at'] ||= Time.at(Time.now.to_i)
111
+ hash['updated_at'] = Time.at(Time.now.to_i)
112
+
113
+ begin
114
+ results = collection.driver.update(
115
+ { :key => the_event.key, :lock_version => the_event.lock_version },
116
+ { "$set" => hash },
117
+ { :upsert => true, :safe => safemode, :multiple => false }
118
+ )
119
+ rescue Mongo::OperationFailure => e
120
+ # upsert = trueだがindexのunique制約があるので重複したkeyは
121
+ # 作成不可、lock_versionの更新失敗はこちらに来る。これは意
122
+ # 図した動作なのでraiseしない。
123
+ Tengine.logger.debug "retrying due to mongodb error #{e}"
124
+ # lock_versionが存在しない可能性(そのような古いDBを引きずっている等)
125
+ collection.driver.update(
126
+ { :key => the_event.key, :lock_version => { "$exists" => false } },
127
+ { "$set" => { :lock_version => -(2**63) } },
128
+ { :upsert => false, :safe => $safemode, :multiple => false }
129
+ )
130
+ else
131
+ if results["error"]
132
+ raise Mongo::OperationFailure, results["error"]
133
+ elsif results["upserted"]
134
+ # *hack* _idを消してupsertしたので、このとき_idは新しくなっている
135
+ the_event.write_attributes "_id" => results["upserted"]
136
+ the_event.reload
137
+ return the_event
138
+ else
139
+ the_event.reload
140
+ return the_event
141
+ end
142
+ end
143
+ end
144
+ end
145
+ end
@@ -0,0 +1,82 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'tengine/core/event'
3
+
4
+ class Tengine::Core::Event::Finder
5
+
6
+ include ::SelectableAttr::Base
7
+
8
+ ATTRIBUTE_NAMES = [
9
+ :event_type_name,
10
+ :key,
11
+ :source_name,
12
+ :occurred_at_start,
13
+ :occurred_at_end,
14
+ :level_ids,
15
+ :confirmed,
16
+ :sender_name,
17
+ :properties,
18
+ :reflesh_interval, # 更新間隔
19
+ ].freeze
20
+
21
+ ATTRIBUTE_NAMES.each{|name| attr_accessor(name)}
22
+
23
+ # 通知レベル
24
+ multi_selectable_attr :level, :enum => Tengine::Core::Event.level_enum
25
+
26
+ def initialize(attrs = {})
27
+ attrs = {
28
+ :level_ids => default_level_ids
29
+ }.update(attrs || {})
30
+ attrs.each do |attr, v|
31
+ send("#{attr}=", v) unless v.blank?
32
+ end
33
+ end
34
+
35
+ def attributes
36
+ ATTRIBUTE_NAMES.inject({}){|d, name| d[name] = send(name); d}
37
+ end
38
+
39
+ # デフォルトでは通知レベルがすべて選択された状態にする
40
+ def default_level_ids
41
+ result = []
42
+ Tengine::Core::Event.level_entries.each do |entry|
43
+ result << entry.id
44
+ end
45
+ return result
46
+ end
47
+
48
+ def paginate(page = nil)
49
+ result = scope(Tengine::Core::Event)
50
+ if page || result.respond_to?(:page)
51
+ result = result.page(page)
52
+ end
53
+ result
54
+ end
55
+
56
+ def scope(criteria)
57
+ result = criteria
58
+ result = result.where(:event_type_name => str_or_regexp(event_type_name)) if event_type_name
59
+ result = result.where(:key => key) if key
60
+ result = result.where(:source_name => str_or_regexp(source_name)) if source_name
61
+ result = result.where(:occurred_at.gte => occurred_at_start) if occurred_at_start
62
+ result = result.where(:occurred_at.lte => occurred_at_end) if occurred_at_end
63
+ result = result.any_in(:level => level_ids) if level_ids
64
+ result = result.where(:confirmed => confirmed) if confirmed
65
+ result = result.where(:sender_name => str_or_regexp(sender_name)) if sender_name
66
+ result = result.where(:properties => properties) if properties
67
+ # ソート
68
+ result = result.desc(:occurred_at)
69
+ result
70
+ end
71
+
72
+ private
73
+ def str_or_regexp(val)
74
+ if val =~ %r{\A\/(.+)\/\Z}
75
+ /#{$1}/
76
+ else
77
+ /\A#{Regexp.escape(val)}/
78
+ end
79
+ end
80
+
81
+ end
82
+
@@ -0,0 +1,88 @@
1
+ require 'tengine/core'
2
+
3
+ module Tengine::Core::EventExceptionReportable
4
+ extend ActiveSupport::Concern
5
+
6
+ FIRE_ALL = lambda do |kernel, dsl_context, event, exception|
7
+ kernel.fire("#{event.event_type_name}.error.tengined",
8
+ :properties => {
9
+ :original_event => event.to_json,
10
+ :error_class_name => exception.class.name,
11
+ :error_message => exception.message,
12
+ :error_backtrace => exception.backtrace,
13
+ # :block_source_location => '%s:%d' % block.source_location,
14
+ })
15
+ end
16
+
17
+ FIRE_EXCEPT_TESTING_ERROR = lambda do |kernel, dsl_context, event, exception|
18
+ if exception.class.name =~ /^Test::|^MiniTest::|^RSpec::|^Spec::/
19
+ raise exception
20
+ else
21
+ FIRE_ALL.call(kernel, dsl_context, event, exception)
22
+ end
23
+ end
24
+
25
+ RAISE_ALL = lambda do |kernel, dsl_context, event, exception|
26
+ raise exception
27
+ end
28
+
29
+ EVENT_EXCEPTION_REPORTERS = {
30
+ :fire_all => FIRE_ALL,
31
+ :raise_all => RAISE_ALL,
32
+ :except_test => FIRE_EXCEPT_TESTING_ERROR,
33
+ }.freeze
34
+
35
+ class << self
36
+ def to_reporter(reporter)
37
+ if reporter.is_a?(Symbol)
38
+ result = EVENT_EXCEPTION_REPORTERS[reporter]
39
+ raise NameError, "Unknown reporter: #{reporter.inspect}" unless result
40
+ result
41
+ elsif reporter.respond_to?(:call)
42
+ reporter
43
+ else
44
+ raise ArgumentError, "Invalid reporter: #{reporter.inspect}"
45
+ end
46
+ end
47
+ end
48
+
49
+ module ClassMethods
50
+ def event_exception_reporter
51
+ unless defined?(@event_exception_reporter)
52
+ @event_exception_reporter = FIRE_ALL
53
+ end
54
+ @event_exception_reporter
55
+ end
56
+
57
+ def event_exception_reporter=(reporter)
58
+ @event_exception_reporter =
59
+ Tengine::Core::EventExceptionReportable.to_reporter(reporter)
60
+ end
61
+
62
+ def temp_exception_reporter(reporter)
63
+ backup = self.event_exception_reporter
64
+ begin
65
+ self.event_exception_reporter = reporter
66
+ yield if block_given?
67
+ ensure
68
+ self.event_exception_reporter = backup
69
+ end
70
+ end
71
+
72
+ end
73
+
74
+ module InstanceMethods
75
+ def report_on_exception(dsl_context, event)
76
+ begin
77
+ yield
78
+ rescue Exception => e
79
+ Tengine.logger.error("[#{e.class.name}] #{e.message}\n " << e.backtrace.join("\n "))
80
+ if reporter = Tengine::Core::Kernel.event_exception_reporter
81
+ reporter.call(self, dsl_context, event, e)
82
+ end
83
+ end
84
+ end
85
+
86
+ end
87
+
88
+ end
@@ -0,0 +1,21 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'tengine/core'
3
+
4
+ class Tengine::Core::EventWrapper
5
+
6
+ def initialize(source)
7
+ @source = source
8
+ end
9
+
10
+ [:event_type_name, :key, :source_name, :occurred_at,
11
+ :level, :confirmed, :sender_name, :properties,].each do |attr_name|
12
+ class_eval(<<-EOS)
13
+ def #{attr_name}; @source.#{attr_name}; end
14
+ EOS
15
+ end
16
+
17
+ def [](key)
18
+ properties[key.to_s]
19
+ end
20
+
21
+ end