tengine_core 0.5.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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,91 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'tengine/core'
3
+
4
+ module Tengine::Core::KernelRuntime # Kernelにincludeされます
5
+
6
+ def safety_processing_headers(headers, event, ack_policy)
7
+ @ack_called = false
8
+ @processing_headers, @event, @ack_policy = headers, event, ack_policy
9
+ begin
10
+ yield if block_given?
11
+ ensure
12
+ @processing_headers, @event, @ack_policy = nil, nil, nil
13
+ end
14
+ end
15
+
16
+ def ack_policies
17
+ @ack_policies ||= { }
18
+ end
19
+
20
+ def add_ack_policy(event_type_name, policy)
21
+ ack_policies[event_type_name.to_s] = policy.to_sym
22
+ end
23
+
24
+ def ack_policy_for(event)
25
+ Tengine.logger.debug("ack_policies: #{ack_policies.inspect}")
26
+ ack_policy = ack_policies[event.event_type_name.to_s] || :at_first
27
+ end
28
+
29
+ def ack
30
+ unless @ack_called
31
+ @ack_called = true
32
+ @processing_headers.ack
33
+ end
34
+ end
35
+
36
+ def ack?
37
+ @ack_called
38
+ end
39
+
40
+
41
+ def submit
42
+ if @submitted_handlers
43
+ @submitted_handlers << @handler
44
+ end
45
+ end
46
+
47
+ def all_submitted?
48
+ return false if @submitted_handlers.nil? || @handlers.nil?
49
+ (@handlers - @submitted_handlers).empty?
50
+ end
51
+
52
+
53
+ def processing_event?; @processing_event; end
54
+
55
+
56
+ def em_setup_blocks
57
+ @em_setup_blocks ||= []
58
+ end
59
+
60
+ private
61
+
62
+ def safety_processing_event(headers)
63
+ @processing_event = true
64
+ begin
65
+ yield if block_given?
66
+ ensure
67
+ @processing_event = false
68
+ end
69
+ end
70
+
71
+ def safty_handlers(handlers)
72
+ @handlers = handlers
73
+ @submitted_handlers = (@ack_policy == :after_all_handler_submit ? [] : nil)
74
+ begin
75
+ yield if block_given?
76
+ ensure
77
+ @handlers = nil
78
+ end
79
+ end
80
+
81
+ def safety_handler(handler)
82
+ @handler = handler
83
+ @submitted_handler = nil
84
+ begin
85
+ yield if block_given?
86
+ ensure
87
+ @handler = nil
88
+ end
89
+ end
90
+
91
+ end
@@ -0,0 +1,38 @@
1
+ require 'tengine/core'
2
+
3
+ module Tengine::Core::MethodTraceable
4
+
5
+ class << self
6
+ attr_accessor :disabled
7
+ end
8
+
9
+ def method_trace(*symbols)
10
+ symbols.each do |symbol|
11
+ original_method = :"_unmethod_traceable_#{symbol}"
12
+ class_eval(<<-EOS, __FILE__, __LINE__ +1)
13
+ if method_defined?(:#{original_method}) # if method_defined?(:_unmemoized_mime_type)
14
+ raise "Already method_tracing #{symbol}" # raise "Already memoized mime_type"
15
+ end # end
16
+ alias #{original_method} #{symbol} # alias _unmemoized_mime_type mime_type
17
+
18
+ def #{symbol}(*args, &block)
19
+ disabled = Tengine::Core::MethodTraceable.disabled
20
+ begin
21
+ Tengine::Core::stdout_logger.info("\#{self.class.name}##{symbol} called") unless disabled
22
+ result = #{original_method}(*args, &block)
23
+ Tengine::Core::stdout_logger.info("\#{self.class.name}##{symbol} complete") unless disabled
24
+ return result
25
+ rescue Exception => e
26
+ unless e.instance_variable_get(:@__traced__) || disabled
27
+ Tengine::Core::stderr_logger.error("\#{self.class.name}##{symbol} failure. [\#{e.class.name}] \#{e.message}\n " << e.backtrace.join("\n "))
28
+ e.instance_variable_set(:@__traced__, true)
29
+ end
30
+ raise
31
+ end
32
+ end
33
+
34
+ EOS
35
+ end
36
+ end
37
+
38
+ end
@@ -0,0 +1,19 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'tengine_core'
3
+ require 'mongoid'
4
+ require 'mongoid/version'
5
+ require 'mongoid/cursor'
6
+
7
+ if Mongoid::VERSION <= "3.0.0"
8
+ class Mongoid::Cursor
9
+ # https://github.com/mongoid/mongoid/pull/1609
10
+ def each
11
+ loop do
12
+ retry_on_connection_failure do
13
+ return unless document = cursor.next
14
+ yield Mongoid::Factory.from_db(klass, document)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,177 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'tengine/core'
3
+
4
+ # Tengine::Core::Mutexは(若干残念な実装の)分散ロック機構です。これを用
5
+ # いることで、とあるMutexをロックしているプロセスを同時にたかだか一つに
6
+ # 制限することが可能になります。
7
+ #
8
+ # mutex = Tengine::Core::Mutex.new "foo"
9
+ # mutex.synchronize do
10
+ # ...
11
+ # end
12
+ #
13
+ # #### 問題点 ####
14
+ #
15
+ # このクラスは正しく使わないと正しく使えません。
16
+ #
17
+ # * スケールしません。当然の話ですが一カ所につき一つのプロセスしか動か
18
+ # ないので、何個プロセスを並列に動かしても無駄です。
19
+ #
20
+ # * トランザクションではありません。あくまでプロセスが同時に動くのを止
21
+ # めているだけです。データの整合性に関していっさい感知できません。
22
+ #
23
+ # * スピンロックです。MongoDBの制限による。したがって非効率です。
24
+ #
25
+ # * ロックしているプロセスが何かの弾みで死ぬかもしれないわけです。そう
26
+ # すると誰もアンロックできなくて詰みます。これを避けるために、一定の
27
+ # 時間がたつとロックは勝手に外れるようになっています(一番残念な部分)。
28
+ # 長時間ロックするようなプロセスは勝手にロックが外れないようにときど
29
+ # きロックを更新する必要があります。これにはheartbeatを使います。
30
+ #
31
+ # mutex.synchronize do
32
+ # ...
33
+ # mutex.heartbeat
34
+ # ...
35
+ # mutex.heartbeat
36
+ # ...
37
+ # mutex.heartbeat
38
+ # ...
39
+ # end
40
+
41
+ ################################################################################
42
+
43
+ # Poor man's distributed lock.
44
+ Tengine::Core::Mutex = Struct.new :mutex, :_id, :recursive
45
+
46
+ # @api private
47
+ class Tengine::Core::Mutex::Mutex
48
+
49
+ include Mongoid::Document
50
+
51
+ field :ttl, :type => Float
52
+ field :waiters, :type => Array
53
+
54
+ def self.find_or_create name, ttl
55
+ collection.driver.update(
56
+ { :_id => name },
57
+ { "$set" => { :ttl => ttl, }, },
58
+ { :upsert => true, :safe => true, :multiple => false, }
59
+ )
60
+ return find(name)
61
+ end
62
+
63
+ private
64
+
65
+ # 暫定対応[Bug]mongodbフェールオーバ中にtengine_resource_watchdが落ちてしまう
66
+ def _update q = {}, r
67
+ retry_count = 100
68
+ idx = 1
69
+ begin
70
+ self.class.collection.driver.update({ :_id => _id, }.update(q), r, {:safe=>true})
71
+ reload
72
+ rescue Mongo::ConnectionFailure => e
73
+ idx += 1
74
+ sleep 0.5
75
+ retry if retry_count > idx
76
+ end
77
+ end
78
+
79
+ public
80
+
81
+ # delete stale locks
82
+ def invalidate
83
+ # can this be done via standard mongoid queries?
84
+ _update("$pull" => { :waiters => { :timeout => { "$lt" => Time.now, }, }, } )
85
+ end
86
+
87
+ # attempt to gain lock
88
+ def lock id
89
+ _update("$push" => { :waiters => { :_id => id._id, :timeout => Time.now + ttl, }, })
90
+ end
91
+
92
+ # attempt to release lock
93
+ def unlock id
94
+ _update("$pull" => { :waiters => { :_id => id._id, }, })
95
+ end
96
+
97
+ # attempt to refresh lock
98
+ def heartbeat id
99
+ _update(
100
+ { :_id => _id, "waiters._id" => id._id, },
101
+ { "$set" => { "waiters.$.timeout" => Time.now + ttl, }, }
102
+ )
103
+ end
104
+ end
105
+
106
+ class Tengine::Core::Mutex
107
+
108
+ class << self
109
+
110
+ alias oldnew new
111
+ private :oldnew
112
+
113
+ # @param [String] name Mutex name. One process at once can gain a lock against a name.
114
+ # @param [Numeric] ttl Time to auto-release a gained lock.
115
+ # @return [Tengine::Core::Mutex] An instance.
116
+ def new name, ttl=2.048
117
+ t = 0.0 + ttl # type check
118
+ raise TypeError, "finite numeric expected (got #{t})" unless t.finite?
119
+ raise ArgumentError, "TTL doesn't make sense." unless t > 0
120
+
121
+ return oldnew(Tengine::Core::Mutex::Mutex.find_or_create(name, t), BSON::ObjectId.new, 0)
122
+ end
123
+ end
124
+
125
+ private
126
+
127
+ def lock_attempt
128
+ m = mutex
129
+ m.invalidate
130
+ m.lock self
131
+ return m.waiters.first["_id"] == _id
132
+ end
133
+
134
+ def lock
135
+ if lock_attempt
136
+ self.recursive += 1
137
+ end
138
+ end
139
+
140
+ def unlock
141
+ self.recursive -= 1
142
+ if self.recursive <= 0
143
+ mutex.unlock self
144
+ end
145
+ end
146
+
147
+ public
148
+
149
+ # delays until you get a lock.
150
+ def synchronize
151
+ raise ArgumentError, "no block given" unless block_given?
152
+
153
+ if lock
154
+ # OK, locked
155
+ EM.schedule do
156
+ begin
157
+ heartbeat
158
+ yield
159
+ ensure
160
+ unlock
161
+ end
162
+ end
163
+ else
164
+ # NG, try again later
165
+ EM.add_timer mutex.ttl do
166
+ synchronize do
167
+ yield
168
+ end
169
+ end
170
+ end
171
+ end
172
+
173
+ # If you need to lock it longer than ttl, call this and you can refresh the ttl.
174
+ def heartbeat
175
+ mutex.heartbeat self
176
+ end
177
+ end
@@ -0,0 +1,69 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'tengine/core'
3
+
4
+ require 'active_support/core_ext/array/extract_options'
5
+
6
+ module Tengine::Core::OptimisticLock
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ cattr_accessor :lock_optimistically, :instance_writer => false
11
+ self.lock_optimistically = true
12
+
13
+ class << self
14
+ alias_method :locking_field=, :set_locking_field
15
+ end
16
+ end
17
+
18
+ class RetryOverError < StandardError
19
+ end
20
+
21
+ def update_with_lock(options = {})
22
+ retry_count = options[:retry] || 5
23
+ idx = 1
24
+ while idx <= retry_count
25
+ yield
26
+ return if __find_and_modify__
27
+ reload
28
+ idx += 1
29
+ end
30
+ raise RetryOverError, "retried #{retry_count} times but failed to update"
31
+ end
32
+
33
+ def __find_and_modify__
34
+ lock_field_name = self.class.locking_field
35
+ current_version = self.send(lock_field_name)
36
+ hash = as_document.dup
37
+ new_version = current_version + 1
38
+ hash[lock_field_name] = new_version
39
+ result = self.class.collection.find_and_modify({
40
+ :query => {:_id => self.id, lock_field_name.to_sym => current_version},
41
+ :update => hash
42
+ })
43
+ send("#{lock_field_name}=", new_version)
44
+ result
45
+ end
46
+
47
+ # ActiveRecord::Locking::Optimistic::ClassMethods を参考に実装しています
48
+ # https://github.com/rails/rails/blob/master/activerecord/lib/active_record/locking/optimistic.rb
49
+ module ClassMethods
50
+ DEFAULT_LOCKING_FIELD = 'lock_version'.freeze
51
+
52
+ # Set the field to use for optimistic locking. Defaults to +lock_version+.
53
+ def set_locking_field(value = nil, &block)
54
+ define_attr_method :locking_field, value, &block
55
+ value
56
+ end
57
+
58
+ # The version field used for optimistic locking. Defaults to +lock_version+.
59
+ def locking_field
60
+ reset_locking_field
61
+ end
62
+
63
+ # Reset the field used for optimistic locking back to the +lock_version+ default.
64
+ def reset_locking_field
65
+ set_locking_field DEFAULT_LOCKING_FIELD
66
+ end
67
+ end
68
+
69
+ end
@@ -0,0 +1,54 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'tengine/core'
3
+
4
+ class Tengine::Core::Plugins
5
+ attr_reader :modules
6
+
7
+ def initialize
8
+ @modules = []
9
+ end
10
+
11
+ def add(plugin_module)
12
+ return if modules.include?(plugin_module)
13
+ Tengine::Core.stdout_logger.info("#{self.class.name}#add(#{plugin_module.name})")
14
+ modules << plugin_module
15
+ enable_plugin(plugin_module)
16
+ plugin_module
17
+ end
18
+
19
+ def notify(sender, msg)
20
+ if block_given?
21
+ notify(sender, :"before_#{msg}")
22
+ yield
23
+ notify(sender, :"after_#{msg}")
24
+ else
25
+ modules.each do |m|
26
+ m.notify(sender, msg) if m.respond_to?(:notify)
27
+ end
28
+ end
29
+ end
30
+
31
+
32
+ # 自動でログ出力する
33
+ extend Tengine::Core::MethodTraceable
34
+ method_trace(:add)
35
+
36
+ private
37
+ def enable_plugin(plugin_module)
38
+ if loader = find_sub_module(plugin_module, :DslLoader, :dsl_loader)
39
+ # Tengine::Core::DslLoadingContext.send(:include, loader)
40
+ Tengine::Core::Kernel.top.singleton_class.send(:include, loader)
41
+ end
42
+ if binder = find_sub_module(plugin_module, :DslBinder, :dsl_binder)
43
+ # Tengine::Core::DslBindingContext.send(:include, binder)
44
+ # Tengine::Core::Kernel.top.singleton_class.send(:include, binder)
45
+ end
46
+ end
47
+
48
+ private
49
+ def find_sub_module(plugin_module, const_name, method_name)
50
+ plugin_module.const_defined?(const_name) ? plugin_module.const_get(const_name) :
51
+ plugin_module.respond_to?(method_name) ? plugin_module.send(method_name) : nil
52
+ end
53
+
54
+ end