state_flow 0.2.0 → 0.2.1
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.
- data/VERSION +1 -1
- data/lib/state_flow.rb +2 -0
- data/lib/state_flow/action.rb +3 -4
- data/lib/state_flow/base.rb +11 -1
- data/lib/state_flow/context.rb +114 -7
- data/lib/state_flow/element.rb +7 -4
- data/lib/state_flow/event_client.rb +0 -17
- data/lib/state_flow/exception_handler.rb +5 -3
- data/lib/state_flow/exception_handler_client.rb +23 -8
- data/lib/state_flow/named_event.rb +2 -2
- data/lib/state_flow/recoverable_exception.rb +12 -0
- data/lib/state_flow/state.rb +6 -5
- data/spec/order_spec.rb +71 -3
- data/spec/resources/models/order.rb +18 -2
- metadata +3 -2
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.2.
|
1
|
+
0.2.1
|
data/lib/state_flow.rb
CHANGED
@@ -20,6 +20,7 @@ module StateFlow
|
|
20
20
|
autoload :ActionEvent, 'state_flow/action_event'
|
21
21
|
autoload :ExceptionHandler, 'state_flow/exception_handler'
|
22
22
|
autoload :ExceptionHandlerClient, 'state_flow/exception_handler_client'
|
23
|
+
autoload :RecoverableException, 'state_flow/recoverable_exception'
|
23
24
|
|
24
25
|
autoload :Log, 'state_flow/log'
|
25
26
|
|
@@ -27,6 +28,7 @@ module StateFlow
|
|
27
28
|
|
28
29
|
def self.included(mod)
|
29
30
|
mod.module_eval do
|
31
|
+
include(Base::ClientInstanceMethods)
|
30
32
|
extend(Base::ClientClassMethods)
|
31
33
|
end
|
32
34
|
end
|
data/lib/state_flow/action.rb
CHANGED
@@ -19,10 +19,9 @@ module StateFlow
|
|
19
19
|
exception_handling(context) do
|
20
20
|
result = context.record_send(method_name, *method_args)
|
21
21
|
event = event_for_action_result(result)
|
22
|
-
if event
|
23
|
-
|
24
|
-
|
25
|
-
action.process(context)
|
22
|
+
event.process(context) if event
|
23
|
+
unless event
|
24
|
+
action.process(context) if action
|
26
25
|
end
|
27
26
|
update_to_destination(context)
|
28
27
|
end
|
data/lib/state_flow/base.rb
CHANGED
@@ -4,6 +4,13 @@ module StateFlow
|
|
4
4
|
|
5
5
|
class Base
|
6
6
|
|
7
|
+
module ClientInstanceMethods
|
8
|
+
def state_flow_contexts
|
9
|
+
@state_flow_contexts ||= {}
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
|
7
14
|
module ClientClassMethods
|
8
15
|
def state_flow_for(selectable_attr)
|
9
16
|
return nil unless @state_flows
|
@@ -20,8 +27,9 @@ module StateFlow
|
|
20
27
|
@state_flows << flow
|
21
28
|
module_eval(<<-EOS, __FILE__, __LINE__)
|
22
29
|
def process_#{selectable_attr}(context_or_options = nil)
|
23
|
-
flow = self.class.state_flow_for(:#{
|
30
|
+
flow = self.class.state_flow_for(:#{flow.attr_name})
|
24
31
|
context = flow.prepare_context(self, context_or_options)
|
32
|
+
state_flow_contexts[:#{selectable_attr}] = context
|
25
33
|
context.process(flow)
|
26
34
|
end
|
27
35
|
EOS
|
@@ -97,7 +105,9 @@ module StateFlow
|
|
97
105
|
|
98
106
|
def process(context)
|
99
107
|
current_key = context.current_attr_key
|
108
|
+
raise ArgumentError, "current_key not found for: #{context.inspect}" unless current_key
|
100
109
|
state = concrete_states[current_key]
|
110
|
+
raise ArgumentError, "status not found for: #{current_key.inspect}" unless state
|
101
111
|
state.process(context)
|
102
112
|
context
|
103
113
|
end
|
data/lib/state_flow/context.rb
CHANGED
@@ -13,7 +13,7 @@ module StateFlow
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def process(flow_or_named_event = flow)
|
16
|
-
|
16
|
+
transaction_with_recovering do
|
17
17
|
flow_or_named_event.process(self)
|
18
18
|
save_record_if_need
|
19
19
|
end
|
@@ -21,8 +21,10 @@ module StateFlow
|
|
21
21
|
last_current_key = current_attr_key
|
22
22
|
while true
|
23
23
|
@mark_proceeding = false
|
24
|
-
|
25
|
-
|
24
|
+
transaction_with_recovering do
|
25
|
+
flow.process(self)
|
26
|
+
save_record_if_need if @mark_proceeding
|
27
|
+
end
|
26
28
|
break unless @mark_proceeding
|
27
29
|
break if last_current_key == current_attr_key
|
28
30
|
last_current_key = current_attr_key
|
@@ -30,12 +32,39 @@ module StateFlow
|
|
30
32
|
end
|
31
33
|
self
|
32
34
|
end
|
35
|
+
|
36
|
+
private
|
37
|
+
def transaction_with_recovering(&block)
|
38
|
+
begin
|
39
|
+
flow.klass.transaction(&block)
|
40
|
+
rescue ::StateFlow::RecoverableException => exception
|
41
|
+
handler = exception.recover_handler
|
42
|
+
log_with_stack_trace(:info, "RECOVERING START", :backtrace => true, :exception => exception, :recover_handler => handler)
|
43
|
+
start_force_recovering
|
44
|
+
begin
|
45
|
+
transaction_with_recovering do
|
46
|
+
handler.process(self)
|
47
|
+
save_record_if_need
|
48
|
+
end
|
49
|
+
log_with_stack_trace(:info, "RECOVERED", :backtrace => false, :exception => exception, :recover_handler => handler)
|
50
|
+
rescue Exception => exception
|
51
|
+
exceptions << exception
|
52
|
+
trace(exception)
|
53
|
+
log_with_stack_trace(:warn, "RECOVERING FAILURE!!!!!", :backtrace => true, :exception => exception, :recover_handler => handler)
|
54
|
+
raise
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
33
59
|
|
60
|
+
public
|
61
|
+
|
34
62
|
def mark_proceeding
|
35
63
|
@mark_proceeding = true
|
36
64
|
end
|
37
65
|
|
38
66
|
def trace(object)
|
67
|
+
ActiveRecord::Base.logger.debug(object.inspect)
|
39
68
|
stack_trace << object
|
40
69
|
end
|
41
70
|
|
@@ -43,22 +72,100 @@ module StateFlow
|
|
43
72
|
@stack_trace ||= []
|
44
73
|
end
|
45
74
|
|
75
|
+
def stack_trace_inspects
|
76
|
+
stack_trace.map{|st| st.inspect}
|
77
|
+
end
|
78
|
+
|
79
|
+
def start_force_recovering ; @force_recovering = true ; end
|
80
|
+
def finish_force_recovering; @force_recovering = false; end
|
81
|
+
def force_recovering?; @force_recovering; end
|
82
|
+
|
83
|
+
def with_force_recovering(target = nil, *recovering_method_and_args)
|
84
|
+
return yield unless force_recovering?
|
85
|
+
begin
|
86
|
+
return yield
|
87
|
+
rescue Exception => exception
|
88
|
+
log_with_stack_trace(:warn, "IGNORE EXCEPTION IN RECOVERING",
|
89
|
+
:exception => exception, :backtrace => true)
|
90
|
+
if recovering_method_and_args.empty?
|
91
|
+
return
|
92
|
+
else
|
93
|
+
return target.send(*recovering_method_and_args)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
|
99
|
+
def log_with_stack_trace(level, *messages)
|
100
|
+
options = messages.extract_options!
|
101
|
+
exception = options.delete(:exception)
|
102
|
+
backtrace = options.delete(:backtrace)
|
103
|
+
result = "#{messages.shift}"
|
104
|
+
result << "\n exception: #{exception.inspect}" if exception
|
105
|
+
messages.each do |msg|
|
106
|
+
result << "\n #{msg}"
|
107
|
+
end
|
108
|
+
options.each do |key, value|
|
109
|
+
result << "\n #{key.inspect}: #{value.inspect}"
|
110
|
+
end
|
111
|
+
if exception && backtrace
|
112
|
+
result << "\n exception.backtrace:\n " << exception.backtrace.join("\n ")
|
113
|
+
end
|
114
|
+
result << "\n context.stack_trace:\n " << stack_trace_inspects.reverse.join("\n ")
|
115
|
+
ActiveRecord::Base.logger.send(level, result)
|
116
|
+
end
|
117
|
+
|
118
|
+
class Manipulation
|
119
|
+
attr_reader :target, :method, :args, :block
|
120
|
+
attr_reader :trace, :result
|
121
|
+
attr_reader :context
|
122
|
+
def initialize(context, target, method, *args, &block)
|
123
|
+
@context = context
|
124
|
+
@target, @method, @args, @block = target, method, args, block
|
125
|
+
@trace = caller(3)
|
126
|
+
end
|
127
|
+
|
128
|
+
def execute
|
129
|
+
begin
|
130
|
+
return @result = @target.send(@method, *@args, &@block)
|
131
|
+
rescue Exception
|
132
|
+
raise unless @context.force_recovering?
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
def inspect
|
137
|
+
args_part = @args.inspect.gsub(/^\[|\]$/, '')
|
138
|
+
if !args_part.nil? && !args_part.empty?
|
139
|
+
args_part = "(#{args_part})"
|
140
|
+
end
|
141
|
+
"#{@target.class.name}##{@method}#{args_part}#{@block ? " with block" : nil}"
|
142
|
+
end
|
143
|
+
end
|
46
144
|
|
47
145
|
def save_record_if_need
|
48
146
|
return unless options[:save]
|
49
|
-
|
147
|
+
manipulation = Manipulation.new(self, record, options[:save])
|
148
|
+
trace(manipulation)
|
149
|
+
manipulation.execute
|
50
150
|
end
|
51
151
|
|
52
152
|
def record_send(*args, &block)
|
53
|
-
|
153
|
+
manipulation = Manipulation.new(self, record, *args, &block)
|
154
|
+
trace(manipulation)
|
155
|
+
manipulation.execute
|
54
156
|
end
|
55
157
|
|
56
158
|
def record_reload_if_possible
|
57
|
-
|
159
|
+
return if record.new_record?
|
160
|
+
manipulation = Manipulation.new(self, record, :reload)
|
161
|
+
trace(manipulation)
|
162
|
+
manipulation.execute
|
58
163
|
end
|
59
164
|
|
60
165
|
def transaction_rollback
|
61
|
-
record.class.connection
|
166
|
+
manipulation = Manipulation.new(self, record.class.connection, :rollback_db_transaction)
|
167
|
+
trace(manipulation)
|
168
|
+
manipulation.execute
|
62
169
|
end
|
63
170
|
|
64
171
|
def exceptions
|
data/lib/state_flow/element.rb
CHANGED
@@ -30,6 +30,11 @@ module StateFlow
|
|
30
30
|
context.record_send("#{flow.attr_key_name}=", destination)
|
31
31
|
end
|
32
32
|
|
33
|
+
def retry_in_recovering(context)
|
34
|
+
update_to_destination(context)
|
35
|
+
end
|
36
|
+
|
37
|
+
|
33
38
|
class << self
|
34
39
|
def uninspected_var(*vars)
|
35
40
|
@@uninspected_var_hash ||= {}
|
@@ -41,8 +46,8 @@ module StateFlow
|
|
41
46
|
@uninspected_vars ||= @@uninspected_var_hash.nil? ? %w(@flow @origin) :
|
42
47
|
self.ancestors.map{|klass| @@uninspected_var_hash[klass] || []}.flatten
|
43
48
|
end
|
44
|
-
|
45
|
-
|
49
|
+
end
|
50
|
+
self.uninspected_var :flow, :origin, :events, :guards, :action
|
46
51
|
|
47
52
|
def inspect
|
48
53
|
vars = (instance_variables - self.class.uninspected_vars).map do |name|
|
@@ -52,8 +57,6 @@ module StateFlow
|
|
52
57
|
vars.unshift("%s:%#x" % [self.class.name, self.object_id])
|
53
58
|
"#<#{vars.join(' ')}>"
|
54
59
|
end
|
55
|
-
|
56
|
-
|
57
60
|
|
58
61
|
end
|
59
62
|
|
@@ -65,23 +65,6 @@ module StateFlow
|
|
65
65
|
def event_for_action_result(result)
|
66
66
|
events.detect{|ev| ev.match?(result)}
|
67
67
|
end
|
68
|
-
|
69
|
-
def exception_handling(context)
|
70
|
-
begin
|
71
|
-
yield
|
72
|
-
rescue Exception => exception
|
73
|
-
context.exceptions << exception
|
74
|
-
context.trace(exception)
|
75
|
-
handlers = events.select{|ev| ev.is_a?(ExceptionHandler)}
|
76
|
-
handlers.each do |handler|
|
77
|
-
next unless handler.match?(exception)
|
78
|
-
handler.process(context)
|
79
|
-
break
|
80
|
-
end
|
81
|
-
raise exception unless context.recovered?(exception)
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
68
|
end
|
86
69
|
|
87
70
|
|
@@ -4,7 +4,7 @@ module StateFlow
|
|
4
4
|
|
5
5
|
class ExceptionHandler < Event
|
6
6
|
attr_reader :exceptions
|
7
|
-
attr_reader :recovering, :rolling_back, :logging_error
|
7
|
+
attr_reader :recovering, :rolling_back, :logging_error, :raise_error_in_handling
|
8
8
|
|
9
9
|
def initialize(origin, *exceptions, &block)
|
10
10
|
options = exceptions.extract_options!
|
@@ -13,6 +13,8 @@ module StateFlow
|
|
13
13
|
@recovering = options[:recovering] || false
|
14
14
|
@rolling_back = options[:rolling_back] || options[:rollback] || false
|
15
15
|
@logging_error = options[:logging]
|
16
|
+
# 例外をハンドリングしている最中にエラーが出た場合にraiseするかどうか。デフォルトnil
|
17
|
+
@raise_error_in_handling = options[:raise_error_in_handling]
|
16
18
|
end
|
17
19
|
|
18
20
|
def match?(exception)
|
@@ -22,8 +24,8 @@ module StateFlow
|
|
22
24
|
|
23
25
|
def process(context)
|
24
26
|
context.recovered_exceptions << context.exceptions.last if recovering
|
25
|
-
context.
|
26
|
-
context.
|
27
|
+
context.record_reload_if_possible # rollbackよりもreloadが先じゃないとネストしたtransactionでおかしい場合がある?
|
28
|
+
# context.transaction_rollback if rolling_back
|
27
29
|
super
|
28
30
|
end
|
29
31
|
|
@@ -3,19 +3,34 @@ require 'state_flow'
|
|
3
3
|
module StateFlow
|
4
4
|
|
5
5
|
module ExceptionHandlerClient
|
6
|
-
|
6
|
+
# 例外ハンドラの配列を返します。
|
7
|
+
# StateFlow::Stateはこれを上書きして親のハンドラも含めて返します。
|
8
|
+
def exception_handlers
|
9
|
+
events.select{|ev| ev.is_a?(ExceptionHandler)}
|
10
|
+
end
|
11
|
+
|
12
|
+
def exception_handling(context, &block)
|
13
|
+
if context.force_recovering?
|
14
|
+
return context.with_force_recovering(self, :retry_in_recovering, context, &block)
|
15
|
+
end
|
16
|
+
|
17
|
+
handlers = exception_handlers
|
18
|
+
return yield if handlers.empty?
|
19
|
+
ActiveRecord::Base.logger.debug("---- exception_handling BEGIN by #{self.inspect}")
|
7
20
|
begin
|
8
|
-
yield
|
21
|
+
return yield
|
22
|
+
ActiveRecord::Base.logger.debug("---- exception_handling END by #{self.inspect}")
|
9
23
|
rescue Exception => exception
|
10
24
|
context.exceptions << exception
|
11
25
|
context.trace(exception)
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
26
|
+
if recover_handler = handlers.detect{|handler| handler.match?(exception)}
|
27
|
+
raise ::StateFlow::RecoverableException.new(recover_handler, exception)
|
28
|
+
else
|
29
|
+
context.log_with_stack_trace(:error, "NOT RECOVERED",
|
30
|
+
:exception => exception, :backtrace => true,
|
31
|
+
:exception_handlers => handlers, :recover_handler => recover_handler)
|
32
|
+
raise exception
|
17
33
|
end
|
18
|
-
raise exception unless context.recovered?(exception)
|
19
34
|
end
|
20
35
|
end
|
21
36
|
|
@@ -10,10 +10,9 @@ module StateFlow
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def process(context)
|
13
|
-
|
13
|
+
state.exception_handling(context) do
|
14
14
|
super
|
15
15
|
end
|
16
|
-
block.call
|
17
16
|
end
|
18
17
|
|
19
18
|
class << self
|
@@ -38,6 +37,7 @@ module StateFlow
|
|
38
37
|
events.each do |event|
|
39
38
|
if event.state.include?(self.send(flow.attr_key_name))
|
40
39
|
context = flow.prepare_context(self, args.first)
|
40
|
+
self.state_flow_contexts[flow.attr_name] = context
|
41
41
|
result = context.process(event)
|
42
42
|
break
|
43
43
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module StateFlow
|
2
|
+
class RecoverableException < Exception
|
3
|
+
attr_reader :recover_handler, :original
|
4
|
+
def initialize(recover_handler, original = nil)
|
5
|
+
@recover_handler = recover_handler
|
6
|
+
@original = original
|
7
|
+
super("#{original ? original.inspect + ' ' : nil}RECOVERABLE by " << recover_handler.inspect)
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
data/lib/state_flow/state.rb
CHANGED
@@ -59,17 +59,18 @@ module StateFlow
|
|
59
59
|
public
|
60
60
|
def process(context)
|
61
61
|
context.trace(self)
|
62
|
-
|
62
|
+
exception_handling(context) do
|
63
63
|
guard = guard_for(context)
|
64
64
|
return guard.process(context) if guard
|
65
65
|
return action.process(context) if action
|
66
66
|
end
|
67
|
-
block.call
|
68
67
|
end
|
69
68
|
|
70
|
-
|
71
|
-
|
72
|
-
|
69
|
+
# override ExceptionHandlerClient#exception_handlers
|
70
|
+
def exception_handlers
|
71
|
+
result = events.select{|ev| ev.is_a?(ExceptionHandler)}
|
72
|
+
result.concat(parent.exception_handlers) if parent
|
73
|
+
result
|
73
74
|
end
|
74
75
|
|
75
76
|
def name_path(separator = '>')
|
data/spec/order_spec.rb
CHANGED
@@ -81,6 +81,44 @@ describe Order do
|
|
81
81
|
Order.count(:conditions => {:status_cd => Order.status_id_by_key(:internal_error)}).should == 1
|
82
82
|
StateFlow::Log.count.should == 0
|
83
83
|
end
|
84
|
+
|
85
|
+
it "cancel_request but raised error and another error during recovering" do
|
86
|
+
@order.should_receive(:send_mail_cancel_requested).and_raise(IOError)
|
87
|
+
@order.should_receive(:send_mail_error).and_raise(IOError)
|
88
|
+
context = @order.cancel_request(:keep_process => false)
|
89
|
+
@order.status_key.should == :internal_error
|
90
|
+
# saveされてます。
|
91
|
+
Order.count.should == 1
|
92
|
+
Order.count(:conditions => {:status_cd => Order.status_id_by_key(:internal_error)}).should == 1
|
93
|
+
StateFlow::Log.count.should == 0
|
94
|
+
end
|
95
|
+
|
96
|
+
it "cancel_request but raised error and another error during recovering #2" do
|
97
|
+
@order.should_receive(:send_mail_cancel_requested).and_raise(IOError)
|
98
|
+
@order.should_receive(:write_exception_to_log).and_raise(IOError)
|
99
|
+
context = @order.cancel_request(:keep_process => false)
|
100
|
+
@order.status_key.should == :internal_error
|
101
|
+
# saveされてます。
|
102
|
+
Order.count.should == 1
|
103
|
+
Order.count(:conditions => {:status_cd => Order.status_id_by_key(:internal_error)}).should == 1
|
104
|
+
StateFlow::Log.count.should == 0
|
105
|
+
end
|
106
|
+
|
107
|
+
it "can access runtime error message in action method" do
|
108
|
+
expected_msg = "実行時に取得しにくいエラー"
|
109
|
+
@order.should_receive(:send_mail_cancel_requested).and_raise(IOError.new(expected_msg))
|
110
|
+
context = @order.cancel_request(:keep_process => false)
|
111
|
+
|
112
|
+
# context.stack_trace.should == []
|
113
|
+
|
114
|
+
@order.status_key.should == :internal_error
|
115
|
+
@order.instance_variable_get(:@last_error_message).should == expected_msg
|
116
|
+
|
117
|
+
# saveされてます。
|
118
|
+
Order.count.should == 1
|
119
|
+
Order.count(:conditions => {:status_cd => Order.status_id_by_key(:internal_error)}).should == 1
|
120
|
+
StateFlow::Log.count.should == 0
|
121
|
+
end
|
84
122
|
end
|
85
123
|
|
86
124
|
describe "credit_card" do
|
@@ -252,11 +290,41 @@ describe Order do
|
|
252
290
|
Order.count(:conditions => {:status_cd => Order.status_id_by_key(:settlement_error)}).should == 1
|
253
291
|
end
|
254
292
|
|
255
|
-
|
256
|
-
|
293
|
+
class TestRuntimeError1 < RuntimeError
|
294
|
+
end
|
295
|
+
|
296
|
+
it "settle failed by RuntimeError" do
|
297
|
+
@order.should_receive(:settle).and_raise(TestRuntimeError1)
|
257
298
|
@order.should_receive(:release_stock)
|
258
299
|
@order.should_receive(:delete_point)
|
259
|
-
@order.process_status_cd
|
300
|
+
context = @order.process_status_cd
|
301
|
+
# context.stack_trace.should == []
|
302
|
+
context.stack_trace[ 0].inspect.should == "Order#status_key"
|
303
|
+
context.stack_trace[ 1].should be_a(StateFlow::State)
|
304
|
+
context.stack_trace[ 1].name_path.should == "valid>auto_cancelable>online_settling"
|
305
|
+
context.stack_trace[ 2].inspect.should == "Order#credit_card?"
|
306
|
+
context.stack_trace[ 3].should be_a(StateFlow::Action)
|
307
|
+
context.stack_trace[ 3].method_name.should == :settle
|
308
|
+
context.stack_trace[ 4].inspect.should == "Order#settle"
|
309
|
+
context.stack_trace[ 5].should be_a(TestRuntimeError1)
|
310
|
+
context.stack_trace[ 6].inspect.should == "Order#reload"
|
311
|
+
# context.stack_trace[ 6].inspect.should == "#{Order.connection.class.name}#rollback_db_transaction"
|
312
|
+
context.stack_trace[ 7].should be_a(StateFlow::ExceptionHandler)
|
313
|
+
context.stack_trace[ 7].exceptions.should == [Exception]
|
314
|
+
context.stack_trace[ 8].should be_a(StateFlow::Action)
|
315
|
+
context.stack_trace[ 8].method_name.should == :release_stock
|
316
|
+
context.stack_trace[ 9].inspect.should == "Order#release_stock"
|
317
|
+
context.stack_trace[10].should be_a(StateFlow::Action)
|
318
|
+
context.stack_trace[10].method_name.should == :delete_point
|
319
|
+
context.stack_trace[11].inspect.should == "Order#delete_point"
|
320
|
+
context.stack_trace[12].inspect.should == "Order#status_key=(:settlement_error)"
|
321
|
+
context.stack_trace[13].inspect.should == "Order#save!"
|
322
|
+
context.stack_trace[14].inspect.should == "Order#status_key"
|
323
|
+
context.stack_trace[15].inspect.should == "Order#status_key"
|
324
|
+
context.stack_trace[16].should be_a(StateFlow::State)
|
325
|
+
context.stack_trace[16].name_path.should == "error>settlement_error"
|
326
|
+
context.stack_trace.length.should == 17
|
327
|
+
|
260
328
|
@order.status_key.should == :settlement_error
|
261
329
|
Order.count.should == 1
|
262
330
|
Order.count(:conditions => {:status_cd => Order.status_id_by_key(:settlement_error)}).should == 1
|
@@ -27,7 +27,7 @@ class Order < ActiveRecord::Base
|
|
27
27
|
# recoverの順番は重要。Exceptionを先に書くと全ての例外は:internal_errorになってしまいます。
|
28
28
|
recover(:'Net::HTTPHeaderSyntaxError').to(:external_error)
|
29
29
|
recover(:'Net::ProtocolError').to(:external_error)
|
30
|
-
recover(:'Exception').to(:internal_error)
|
30
|
+
recover(:'Exception').action(:write_exception_to_log).action(:send_mail_error).to(:internal_error)
|
31
31
|
|
32
32
|
group(:auto_cancelable) do # 自動キャンセル可
|
33
33
|
|
@@ -126,7 +126,6 @@ class Order < ActiveRecord::Base
|
|
126
126
|
|
127
127
|
group(:error) do # 異常系
|
128
128
|
from(:settlement_error) do
|
129
|
-
action(:send_mail_settlement_error)
|
130
129
|
# to(:settlement_error) # 遷移しない
|
131
130
|
end
|
132
131
|
|
@@ -168,4 +167,21 @@ class Order < ActiveRecord::Base
|
|
168
167
|
def send_mail_deliver_notification; end
|
169
168
|
def send_mail_settlement_error; end
|
170
169
|
|
170
|
+
def send_mail_error; end
|
171
|
+
|
172
|
+
# recover(:'Exception') で処理した例外を実行時に参照します。
|
173
|
+
def write_exception_to_log
|
174
|
+
logger.debug "*" * 100
|
175
|
+
logger.debug "write_exception_to_log"
|
176
|
+
|
177
|
+
logger.debug state_flow_contexts.inspect
|
178
|
+
|
179
|
+
if context = state_flow_contexts[:status_cd]
|
180
|
+
logger.debug context.inspect
|
181
|
+
logger.debug context.exceptions.inspect
|
182
|
+
@last_error_message = context.exceptions.last.to_s
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|
186
|
+
|
171
187
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: state_flow
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Takeshi Akima
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-11-
|
12
|
+
date: 2009-11-05 00:00:00 +09:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -46,6 +46,7 @@ files:
|
|
46
46
|
- lib/state_flow/log.rb
|
47
47
|
- lib/state_flow/named_event.rb
|
48
48
|
- lib/state_flow/named_guard.rb
|
49
|
+
- lib/state_flow/recoverable_exception.rb
|
49
50
|
- lib/state_flow/state.rb
|
50
51
|
- spec/.gitignore
|
51
52
|
- spec/database.yml
|