hyper-operation 1.0.alpha1.2 → 1.0.alpha1.7
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.
- checksums.yaml +4 -4
- data/.gitignore +4 -0
- data/.travis.yml +1 -0
- data/hyper-operation.gemspec +6 -4
- data/lib/hyper-operation.rb +4 -1
- data/lib/hyper-operation/api.rb +6 -2
- data/lib/hyper-operation/async_sleep.rb +23 -0
- data/lib/hyper-operation/exception.rb +29 -3
- data/lib/hyper-operation/promise.rb +32 -2
- data/lib/hyper-operation/railway/dispatcher.rb +0 -1
- data/lib/hyper-operation/railway/run.rb +57 -48
- data/lib/hyper-operation/railway/validations.rb +9 -2
- data/lib/hyper-operation/server_op.rb +31 -9
- data/lib/hyper-operation/transport/client_drivers.rb +45 -11
- data/lib/hyper-operation/transport/connection.rb +58 -136
- data/lib/hyper-operation/transport/connection_adapter/active_record.rb +113 -0
- data/lib/hyper-operation/transport/connection_adapter/active_record/auto_create.rb +26 -0
- data/lib/hyper-operation/transport/connection_adapter/active_record/connection.rb +47 -0
- data/lib/hyper-operation/transport/connection_adapter/active_record/queued_message.rb +42 -0
- data/lib/hyper-operation/transport/connection_adapter/redis.rb +94 -0
- data/lib/hyper-operation/transport/connection_adapter/redis/connection.rb +85 -0
- data/lib/hyper-operation/transport/connection_adapter/redis/queued_message.rb +34 -0
- data/lib/hyper-operation/transport/connection_adapter/redis/redis_record.rb +158 -0
- data/lib/hyper-operation/transport/hyperstack.rb +15 -2
- data/lib/hyper-operation/transport/hyperstack_controller.rb +6 -2
- data/lib/hyper-operation/transport/policy.rb +16 -26
- data/lib/hyper-operation/transport/policy_diagnostics.rb +106 -0
- data/lib/hyper-operation/version.rb +1 -1
- metadata +79 -38
- data/Gemfile.lock +0 -385
- data/lib/hyper-operation/delay_and_interval.rb +0 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a56623fa556f5390dc8771aa7364bcf1b28915b29cdefc7bff643815cdeb23f8
|
4
|
+
data.tar.gz: 592ca1144190525c14f98f2e38155942583489b62b94b3605f6707462a1b15f5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 592851310258a5036585eb9c6781955070696810cedd90cdfdaa3ee7f69313cdeb9166fdd0c5e81c37fe63be1074fb275bb7bb522650c473ea2dfc4280f3a0e4
|
7
|
+
data.tar.gz: 34249a102c0f16febeb00e998368d3f358c726045af29ebc8b78431bee96230381ddc6e0fae0576d4a955c40e2bb83b135d9723c33f7af5e62738dd42d5ccdca
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/hyper-operation.gemspec
CHANGED
@@ -27,25 +27,27 @@ Gem::Specification.new do |spec|
|
|
27
27
|
spec.add_dependency 'hyper-component', Hyperstack::Operation::VERSION
|
28
28
|
spec.add_dependency 'mutations'
|
29
29
|
spec.add_dependency 'opal-activesupport', '~> 0.3.1'
|
30
|
+
spec.add_dependency 'tty-table'
|
30
31
|
|
31
32
|
spec.add_development_dependency 'bundler'
|
32
33
|
spec.add_development_dependency 'chromedriver-helper'
|
33
34
|
spec.add_development_dependency 'database_cleaner'
|
34
35
|
spec.add_development_dependency 'hyper-spec', Hyperstack::Operation::VERSION
|
35
36
|
spec.add_development_dependency 'mysql2'
|
36
|
-
spec.add_development_dependency 'opal', '>= 0.11.0', '< 0.12.0'
|
37
37
|
spec.add_development_dependency 'opal-browser', '~> 0.2.0'
|
38
|
-
spec.add_development_dependency 'opal-rails', '
|
38
|
+
spec.add_development_dependency 'opal-rails', '>= 0.9.4', '< 2.0'
|
39
39
|
spec.add_development_dependency 'pry-rescue'
|
40
|
+
spec.add_development_dependency 'pry-stack_explorer'
|
40
41
|
spec.add_development_dependency 'puma'
|
41
42
|
spec.add_development_dependency 'pusher'
|
42
43
|
spec.add_development_dependency 'pusher-fake'
|
43
|
-
spec.add_development_dependency 'rails', '>=
|
44
|
+
spec.add_development_dependency 'rails', ENV['RAILS_VERSION'] || '>= 5.0.0', '< 7.0'
|
44
45
|
spec.add_development_dependency 'rake'
|
45
46
|
spec.add_development_dependency 'react-rails', '>= 2.4.0', '< 2.5.0'
|
47
|
+
spec.add_development_dependency 'redis'
|
46
48
|
spec.add_development_dependency 'rspec-rails'
|
47
49
|
spec.add_development_dependency 'rspec-steps', '~> 2.1.1'
|
48
50
|
spec.add_development_dependency 'rspec-wait'
|
49
|
-
spec.add_development_dependency 'sqlite3'
|
51
|
+
spec.add_development_dependency 'sqlite3', '~> 1.4.2' # see https://github.com/rails/rails/issues/35153
|
50
52
|
spec.add_development_dependency 'timecop', '~> 0.8.1'
|
51
53
|
end
|
data/lib/hyper-operation.rb
CHANGED
@@ -28,7 +28,9 @@ if RUBY_ENGINE == 'opal'
|
|
28
28
|
require 'hyper-operation/railway/validations'
|
29
29
|
require 'hyper-operation/server_op'
|
30
30
|
require 'hyper-operation/boot'
|
31
|
+
require 'hyper-operation/async_sleep'
|
31
32
|
else
|
33
|
+
require 'tty-table'
|
32
34
|
require 'hyperstack-config'
|
33
35
|
require 'mutations'
|
34
36
|
Mutations::HashFilter.register_additional_filter(Mutations::DuckFilter, :duck)
|
@@ -40,10 +42,11 @@ else
|
|
40
42
|
require 'hyper-operation/transport/connection'
|
41
43
|
require 'hyper-operation/transport/hyperstack'
|
42
44
|
require 'hyper-operation/transport/policy'
|
45
|
+
require 'hyper-operation/transport/policy_diagnostics'
|
43
46
|
require 'hyper-operation/transport/client_drivers'
|
44
47
|
require 'hyper-operation/transport/acting_user'
|
45
48
|
require 'opal-activesupport'
|
46
|
-
require 'hyper-operation/
|
49
|
+
require 'hyper-operation/async_sleep'
|
47
50
|
require 'hyper-operation/exception'
|
48
51
|
require 'hyper-operation/promise'
|
49
52
|
require 'hyper-operation/railway'
|
data/lib/hyper-operation/api.rb
CHANGED
@@ -46,8 +46,12 @@ module Hyperstack
|
|
46
46
|
@_railway.process_params(args)
|
47
47
|
@_railway.process_validations
|
48
48
|
@_railway.run
|
49
|
-
|
50
|
-
@_railway.
|
49
|
+
# return the result from dispatch in case there is an error
|
50
|
+
if (dispatch_result = @_railway.dispatch).rejected?
|
51
|
+
dispatch_result
|
52
|
+
else
|
53
|
+
@_railway.result
|
54
|
+
end
|
51
55
|
end
|
52
56
|
end
|
53
57
|
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Hyperstack
|
2
|
+
module AsyncSleep
|
3
|
+
if RUBY_ENGINE == 'opal'
|
4
|
+
def self.every(*args, &block)
|
5
|
+
every(*args, &block)
|
6
|
+
end
|
7
|
+
|
8
|
+
def self.after(*args, &block)
|
9
|
+
after(*args, &block)
|
10
|
+
end
|
11
|
+
else
|
12
|
+
extend self
|
13
|
+
|
14
|
+
def every(time, &block)
|
15
|
+
Thread.new { loop { sleep time; block.call } }
|
16
|
+
end
|
17
|
+
|
18
|
+
def after(time, &block)
|
19
|
+
Thread.new { sleep time; block.call }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -1,13 +1,39 @@
|
|
1
|
+
module Mutations
|
2
|
+
class ErrorArray
|
3
|
+
def self.new_from_error_hash(errors)
|
4
|
+
new(errors.collect do |key, values|
|
5
|
+
ErrorAtom.new(key, values[:symbol], values)
|
6
|
+
end)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
1
11
|
module Hyperstack
|
2
12
|
class AccessViolation < StandardError
|
3
|
-
|
4
|
-
|
13
|
+
attr_accessor :details
|
14
|
+
|
15
|
+
def initialize(message = nil, details = nil)
|
16
|
+
super("Hyperstack::AccessViolation#{':' + message.to_s if message}")
|
17
|
+
@details = details
|
18
|
+
end
|
19
|
+
|
20
|
+
def __hyperstack_on_error(operation, params, fmted_message)
|
21
|
+
Hyperstack.on_error(operation, self, params, fmted_message)
|
5
22
|
end
|
6
23
|
end
|
7
24
|
|
8
25
|
class Operation
|
9
26
|
class ValidationException < Mutations::ValidationException
|
27
|
+
def as_json(*)
|
28
|
+
errors.as_json
|
29
|
+
end
|
30
|
+
|
31
|
+
def initialize(errors)
|
32
|
+
unless errors.is_a? Mutations::ErrorHash
|
33
|
+
errors = Mutations::ErrorArray.new_from_error_hash(errors)
|
34
|
+
end
|
35
|
+
super(errors)
|
36
|
+
end
|
10
37
|
end
|
11
38
|
end
|
12
|
-
|
13
39
|
end
|
@@ -1,3 +1,15 @@
|
|
1
|
+
# Caution. For now Hyperstack maintains its own copy of the Promise class.
|
2
|
+
# Eventually the diff between hyperstacks version and the official Opal version
|
3
|
+
# should be put into a PR.
|
4
|
+
|
5
|
+
# A key feature add is the Fail Exception class which is simply there to allow
|
6
|
+
# a `always` block to reject without raising an error. To use this see the run.rb
|
7
|
+
# module.
|
8
|
+
|
9
|
+
# Also see exception! method for the part of the code that detects the Fail exception.
|
10
|
+
|
11
|
+
# See https://github.com/opal/opal/issues/1967 for details.
|
12
|
+
|
1
13
|
class Promise
|
2
14
|
def self.value(value)
|
3
15
|
new.resolve(value)
|
@@ -11,6 +23,13 @@ class Promise
|
|
11
23
|
When.new(promises)
|
12
24
|
end
|
13
25
|
|
26
|
+
class Fail < StandardError
|
27
|
+
attr_reader :result
|
28
|
+
def initialize(result)
|
29
|
+
@result = result
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
14
33
|
attr_reader :error, :prev, :next
|
15
34
|
|
16
35
|
def initialize(action = {})
|
@@ -104,6 +123,7 @@ class Promise
|
|
104
123
|
|
105
124
|
begin
|
106
125
|
if block = @action[:success] || @action[:always]
|
126
|
+
@realized = :resolve
|
107
127
|
value = block.call(value)
|
108
128
|
end
|
109
129
|
|
@@ -137,6 +157,9 @@ class Promise
|
|
137
157
|
|
138
158
|
begin
|
139
159
|
if block = @action[:failure] || @action[:always]
|
160
|
+
# temporarily set values so always can determine if this
|
161
|
+
# was a reject or resolve
|
162
|
+
@realized = :reject
|
140
163
|
value = block.call(value)
|
141
164
|
end
|
142
165
|
|
@@ -164,8 +187,15 @@ class Promise
|
|
164
187
|
end
|
165
188
|
|
166
189
|
def exception!(error)
|
167
|
-
|
168
|
-
|
190
|
+
# If the error is a Promise::Fail, then
|
191
|
+
# the error becomes the error.result value
|
192
|
+
# this allows code to raise an error on an
|
193
|
+
# object that is not an error.
|
194
|
+
if error.is_a? Promise::Fail
|
195
|
+
error = error.result
|
196
|
+
else
|
197
|
+
@exception = true
|
198
|
+
end
|
169
199
|
reject!(error)
|
170
200
|
end
|
171
201
|
|
@@ -4,10 +4,13 @@ module Hyperstack
|
|
4
4
|
class Exit < StandardError
|
5
5
|
attr_reader :state
|
6
6
|
attr_reader :result
|
7
|
-
def initialize(state, result)
|
7
|
+
def initialize(state, result = nil)
|
8
8
|
@state = state
|
9
9
|
@result = result
|
10
10
|
end
|
11
|
+
def to_s
|
12
|
+
@state
|
13
|
+
end
|
11
14
|
end
|
12
15
|
|
13
16
|
class Railway
|
@@ -21,7 +24,7 @@ module Hyperstack
|
|
21
24
|
@tracks ||= []
|
22
25
|
end
|
23
26
|
|
24
|
-
def
|
27
|
+
def build_tie(tie, args, block)
|
25
28
|
if args.count.zero?
|
26
29
|
{ run: block }
|
27
30
|
elsif args[0].is_a?(Hash)
|
@@ -41,7 +44,7 @@ module Hyperstack
|
|
41
44
|
|
42
45
|
[:step, :failed, :async].each do |tie|
|
43
46
|
define_method :"add_#{tie}" do |*args, &block|
|
44
|
-
tracks <<
|
47
|
+
tracks << build_tie(tie, args, block)
|
45
48
|
end
|
46
49
|
end
|
47
50
|
|
@@ -55,44 +58,36 @@ module Hyperstack
|
|
55
58
|
end
|
56
59
|
|
57
60
|
def step(opts)
|
58
|
-
|
59
|
-
|
60
|
-
@last_result = result
|
61
|
-
apply(opts, :in_promise)
|
62
|
-
end
|
63
|
-
elsif @state == :success
|
64
|
-
apply(opts)
|
65
|
-
end
|
61
|
+
@promise_chain = @promise_chain
|
62
|
+
.then { |result| apply(result, :success, opts) }
|
66
63
|
end
|
67
64
|
|
68
65
|
def failed(opts)
|
69
|
-
|
70
|
-
|
71
|
-
@
|
72
|
-
apply(
|
73
|
-
raise @last_result if @last_result.is_a? Exception
|
74
|
-
raise e
|
66
|
+
@promise_chain = @promise_chain
|
67
|
+
.always do |result|
|
68
|
+
@state = :failed if @promise_chain.rejected? && @state != :abort
|
69
|
+
apply(result, :failed, opts)
|
75
70
|
end
|
76
|
-
elsif @state == :failed
|
77
|
-
apply(opts)
|
78
|
-
end
|
79
71
|
end
|
80
72
|
|
81
73
|
def async(opts)
|
82
|
-
|
74
|
+
@promise_chain = @promise_chain_start = Promise.new
|
75
|
+
@promise_chain.resolve(@last_async_result)
|
76
|
+
step(opts)
|
83
77
|
end
|
84
78
|
|
85
|
-
def apply(
|
79
|
+
def apply(result, state, opts)
|
80
|
+
return result unless @state == state
|
86
81
|
if opts[:scope] == :class
|
87
|
-
args = [@operation,
|
82
|
+
args = [@operation, *result]
|
88
83
|
instance = @operation.class
|
89
84
|
else
|
90
|
-
args =
|
85
|
+
args = result
|
91
86
|
instance = @operation
|
92
87
|
end
|
93
88
|
block = opts[:run]
|
94
89
|
block = instance.method(block) if block.is_a? Symbol
|
95
|
-
|
90
|
+
last_result =
|
96
91
|
if block.arity.zero?
|
97
92
|
instance.instance_exec(&block)
|
98
93
|
elsif args.is_a?(Array) && block.arity == args.count
|
@@ -100,40 +95,54 @@ module Hyperstack
|
|
100
95
|
else
|
101
96
|
instance.instance_exec(args, &block)
|
102
97
|
end
|
103
|
-
|
104
|
-
|
105
|
-
@last_result = @last_result.value if @last_result.resolved?
|
106
|
-
@last_result
|
98
|
+
@last_async_result = last_result unless last_result.is_a? Promise
|
99
|
+
last_result
|
107
100
|
rescue Exit => e
|
108
|
-
|
109
|
-
|
110
|
-
|
101
|
+
# the promise chain ends with an always block which will process
|
102
|
+
# any immediate exits by checking the value of @state. All other
|
103
|
+
# step/failed/async blocks will be skipped because state will not equal
|
104
|
+
# :succeed or :failed
|
105
|
+
if e.state == :failed
|
106
|
+
@state = :abort
|
107
|
+
# exit via the final always block with the exception
|
108
|
+
raise e.result.is_a?(Exception) ? e.result : e
|
109
|
+
else
|
110
|
+
@state = :succeed
|
111
|
+
# exit via the final then block with the success value
|
112
|
+
e.result
|
113
|
+
end
|
111
114
|
rescue Exception => e
|
112
115
|
@state = :failed
|
113
|
-
|
114
|
-
raise e if in_promise
|
116
|
+
raise e
|
115
117
|
end
|
116
118
|
|
117
119
|
def run
|
118
|
-
if @operation.has_errors? || @state
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
120
|
+
# if @operation.has_errors? || @state
|
121
|
+
# @last_result ||= ValidationException.new(@operation.instance_variable_get('@errors'))
|
122
|
+
# # following handles abort out of validation. if state is already set then we are aborting
|
123
|
+
# # otherwise if state is not set but we have errors then we are failed
|
124
|
+
# @state ||= :failed
|
125
|
+
# else
|
126
|
+
# @state = :success
|
127
|
+
# end
|
128
|
+
@state ||= :success
|
129
|
+
@promise_chain_start = @promise_chain = Promise.new
|
130
|
+
@promise_chain_start.resolve(@last_result)
|
131
|
+
tracks.each { |opts| opts[:tie].bind(self).call(opts) } unless @state == :abort
|
127
132
|
end
|
128
133
|
|
129
134
|
def result
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
135
|
+
@result ||= @promise_chain.always do |e|
|
136
|
+
if %i[abort failed].include? @state
|
137
|
+
if e.is_a? Exception
|
138
|
+
raise e
|
139
|
+
else
|
140
|
+
raise Promise::Fail.new(e)
|
141
|
+
end
|
134
142
|
else
|
135
|
-
|
143
|
+
e
|
136
144
|
end
|
145
|
+
end
|
137
146
|
end
|
138
147
|
end
|
139
148
|
end
|
@@ -28,6 +28,8 @@ module Hyperstack
|
|
28
28
|
rescue Exit => e
|
29
29
|
raise e unless e.state == :failed
|
30
30
|
add_error(param, symbol, message)
|
31
|
+
# use a bogus exit state which will skip adding
|
32
|
+
# a validation error (see catch block in process_validations method)
|
31
33
|
raise Exit.new(:abort_from_add_error, e.result)
|
32
34
|
end
|
33
35
|
end
|
@@ -47,17 +49,22 @@ module Hyperstack
|
|
47
49
|
when :failed
|
48
50
|
add_validation_error(i, "param validation #{i+1} aborted")
|
49
51
|
end
|
50
|
-
@state = :
|
52
|
+
@state = :abort
|
51
53
|
return # break does not work in Opal
|
52
54
|
rescue AccessViolation => e
|
53
55
|
add_validation_error(i, e)
|
54
|
-
@state = :
|
56
|
+
@state = :abort
|
55
57
|
@last_result = e
|
56
58
|
return # break does not work in Opal
|
57
59
|
rescue Exception => e
|
58
60
|
add_validation_error(i, e)
|
59
61
|
end
|
60
62
|
end
|
63
|
+
ensure
|
64
|
+
if @operation.has_errors?
|
65
|
+
@last_result ||= ValidationException.new(@operation.instance_variable_get('@errors'))
|
66
|
+
@state ||= :failed
|
67
|
+
end
|
61
68
|
end
|
62
69
|
end
|
63
70
|
end
|