evt-component_host 0.1.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2d2bd4f87854d29af6a297eeff88d89f10eb1280
4
+ data.tar.gz: 9a2ad4c114ff8ad79309617813491a512b10d97c
5
+ SHA512:
6
+ metadata.gz: 58f87556a16591d3f490c81f83020278b152096c6cc98d8439aa5ea258b2fee9d3021187d7de04a45f6f19db17f5460d7b86af42bdddb516ce9c439c1c8028f0
7
+ data.tar.gz: e39f8800e022ebdd72a002cad48f864ca3f8e62f60fe72daed997f60951e8ba7fe963e4ebcacb868d8cb2bfb41cc10b34732a81e911ea75a31c7f376042313e9
@@ -0,0 +1,14 @@
1
+ require 'actor'
2
+ require 'async_invocation'
3
+ require 'casing'
4
+ require 'log'
5
+ require 'virtual'
6
+
7
+ require 'component_host/log'
8
+ require 'component_host/signal'
9
+
10
+ require 'component_host/host'
11
+ require 'component_host/supervisor_observers/log'
12
+ require 'component_host/supervisor_observers/record_errors'
13
+
14
+ require 'component_host/component_host'
@@ -0,0 +1,13 @@
1
+ module ComponentHost
2
+ def self.start(component_name, &block)
3
+ logger = ::Log.get self
4
+
5
+ host = Host.build
6
+
7
+ host.instance_exec host, &block
8
+
9
+ host.start do
10
+ logger.info "Started component: #{component_name} (ProcessID: #{::Process.pid})"
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ require 'component_host/controls/error'
2
+ require 'component_host/controls/process_name'
3
+ require 'component_host/controls/start_component'
4
+ require 'component_host/controls/start_component/actor_crashes'
5
+ require 'component_host/controls/start_component/raises_error'
6
+ require 'component_host/controls/start_component/runs_continuously'
7
+ require 'component_host/controls/start_component/stops_immediately'
@@ -0,0 +1,11 @@
1
+ module ComponentHost
2
+ module Controls
3
+ module Error
4
+ def self.example
5
+ Example.new
6
+ end
7
+
8
+ Example = Class.new StandardError
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ module ComponentHost
2
+ module Controls
3
+ module ProcessName
4
+ def self.example
5
+ 'some-process'
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,23 @@
1
+ module ComponentHost
2
+ module Controls
3
+ module StartComponent
4
+ def self.example
5
+ Example.new
6
+ end
7
+
8
+ class Example
9
+ attr_accessor :executed
10
+
11
+ def call
12
+ self.executed = true
13
+ end
14
+
15
+ module Assertions
16
+ def executed?
17
+ executed ? true : false
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,27 @@
1
+ module ComponentHost
2
+ module Controls
3
+ module StartComponent
4
+ module ActorCrashes
5
+ def self.call
6
+ Actor.start
7
+ end
8
+
9
+ def self.error
10
+ @error ||= Error.example
11
+ end
12
+
13
+ class Actor
14
+ include ::Actor
15
+
16
+ handle :start do
17
+ raise error
18
+ end
19
+
20
+ def error
21
+ ActorCrashes.error
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,15 @@
1
+ module ComponentHost
2
+ module Controls
3
+ module StartComponent
4
+ module RaisesError
5
+ def self.call
6
+ raise error
7
+ end
8
+
9
+ def self.error
10
+ @error ||= Error.example
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,40 @@
1
+ module ComponentHost
2
+ module Controls
3
+ module StartComponent
4
+ module RunsContinuously
5
+ def self.call
6
+ Actor.start
7
+ end
8
+
9
+ class Actor
10
+ include ::Actor
11
+ include ::Log::Dependency
12
+
13
+ attr_writer :counter
14
+
15
+ handle :start do
16
+ :print_heartbeat
17
+ end
18
+
19
+ handle :print_heartbeat do
20
+ logger.info "Heartbeat (Counter: #{counter})"
21
+
22
+ :next
23
+ end
24
+
25
+ handle :next do
26
+ self.counter += 1
27
+
28
+ sleep 1
29
+
30
+ :print_heartbeat
31
+ end
32
+
33
+ def counter
34
+ @counter ||= 0
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,19 @@
1
+ module ComponentHost
2
+ module Controls
3
+ module StartComponent
4
+ module StopsImmediately
5
+ def self.call
6
+ Actor.start
7
+ end
8
+
9
+ class Actor
10
+ include ::Actor
11
+
12
+ handle :start do
13
+ :stop
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,115 @@
1
+ module ComponentHost
2
+ class Host
3
+ include ::Log::Dependency
4
+
5
+ dependency :signal, Signal
6
+ dependency :send, Actor::Messaging::Send
7
+
8
+ def self.build
9
+ instance = new
10
+ Signal.configure instance
11
+ instance.send = Actor::Messaging::Send
12
+ instance
13
+ end
14
+
15
+ def register(start_proc, name=nil, &block)
16
+ start_proc ||= proc { yield }
17
+
18
+ logger.trace { "Registering component (StartProcedure: #{start_proc}, Name: #{name || '(none)'})" }
19
+
20
+ component = Component.new start_proc, name
21
+
22
+ components << component
23
+
24
+ logger.debug { "Component registered (StartProcedure: #{start_proc}, Name: #{name || '(none)'})" }
25
+
26
+ component
27
+ end
28
+
29
+ def record_error(&block)
30
+ record_errors_observer.record_error_proc = block
31
+ end
32
+
33
+ def start(&block)
34
+ started_components = []
35
+
36
+ Actor::Supervisor.start do |supervisor|
37
+ supervisor.add_observer record_errors_observer
38
+
39
+ supervisor.add_observer log_observer
40
+
41
+ signal.trap 'TSTP' do
42
+ message = Actor::Messages::Suspend
43
+
44
+ send.(message, supervisor.address)
45
+
46
+ logger.info { "Handled TSTP signal (MessageName: #{message.message_name}, SupervisorAddress: #{supervisor.address.id})" }
47
+ end
48
+
49
+ signal.trap 'CONT' do
50
+ message = Actor::Messages::Resume
51
+
52
+ send.(message, supervisor.address)
53
+
54
+ logger.info { "Handled CONT signal (MessageName: #{message.message_name}, SupervisorAddress: #{supervisor.address.id})" }
55
+ end
56
+
57
+ signal.trap 'INT' do
58
+ message = Actor::Messages::Shutdown
59
+
60
+ send.(message, supervisor.address)
61
+
62
+ logger.info { "Handled INT signal (MessageName: #{message.message_name}, SupervisorAddress: #{supervisor.address.id})" }
63
+ end
64
+
65
+ start_components do |component|
66
+ started_components << component
67
+ end
68
+
69
+ block.(supervisor) if block
70
+ end
71
+
72
+ started_components
73
+ end
74
+
75
+ def start_components(&block)
76
+ components.each do |component|
77
+ component.start
78
+
79
+ block.(component) if block
80
+ end
81
+
82
+ rescue => error
83
+ record_errors_observer.(error)
84
+ raise error
85
+ end
86
+
87
+ def record_errors_observer
88
+ @record_errors_observer ||= SupervisorObservers::RecordErrors.new
89
+ end
90
+
91
+ def log_observer
92
+ @log_observer ||= SupervisorObservers::Log.new
93
+ end
94
+
95
+ def components
96
+ @components ||= []
97
+ end
98
+
99
+ Component = Struct.new :start_proc, :name do
100
+ def start
101
+ start_proc.()
102
+ end
103
+ end
104
+
105
+ module Assertions
106
+ def registered?(&block)
107
+ block ||= proc { true }
108
+
109
+ components.any? do |component|
110
+ block.(component.start_proc, component.name)
111
+ end
112
+ end
113
+ end
114
+ end
115
+ end
@@ -0,0 +1,8 @@
1
+ module ComponentHost
2
+ class Log < Log
3
+ def tag!(tags)
4
+ tags << :component_host
5
+ tags << :verbose
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,53 @@
1
+ module ComponentHost
2
+ module Signal
3
+ def self.configure(receiver, attr_name: nil)
4
+ attr_name ||= :signal
5
+
6
+ receiver.public_send "#{attr_name}=", ::Signal
7
+ end
8
+
9
+ module Substitute
10
+ def self.build
11
+ Signal.new
12
+ end
13
+
14
+ class Signal
15
+ def trap(signal, &handler)
16
+ handlers[signal] = handler
17
+ end
18
+
19
+ def simulate_signal(signal)
20
+ handler = handlers[signal]
21
+
22
+ return if handler.nil?
23
+
24
+ handler.()
25
+
26
+ record = Record.new signal
27
+ records << record
28
+ record
29
+ end
30
+
31
+ def handlers
32
+ @handlers ||= {}
33
+ end
34
+
35
+ def records
36
+ @records ||= []
37
+ end
38
+
39
+ Record = Struct.new :signal
40
+
41
+ module Assertions
42
+ def trapped?(signal=nil)
43
+ if signal.nil?
44
+ records.any?
45
+ else
46
+ records.any? { |record| record.signal == signal }
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,22 @@
1
+ module ComponentHost
2
+ module SupervisorObservers
3
+ class Log
4
+ include Actor::Supervisor::Observer
5
+ include ComponentHost::Log::Dependency
6
+
7
+ handle Actor::Messages::ActorStarted do |msg|
8
+ logger.debug "Actor started (Address: #{msg.address.id}, Actor: #{msg.actor.digest})"
9
+ end
10
+
11
+ handle Actor::Messages::ActorStopped do |msg|
12
+ logger.debug "Actor stopped (Address: #{msg.address.id}, Actor: #{msg.actor.digest})"
13
+ end
14
+
15
+ handle Actor::Messages::ActorCrashed do |msg|
16
+ error = msg.error
17
+
18
+ logger.error "Error raised (ErrorClass: #{error.class.name}, Actor: #{msg.actor.digest}, Message: #{error.message.inspect})"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,23 @@
1
+ module ComponentHost
2
+ module SupervisorObservers
3
+ class RecordErrors
4
+ include Actor::Supervisor::Observer
5
+
6
+ attr_writer :record_error_proc
7
+
8
+ handle Actor::Messages::ActorCrashed do |msg|
9
+ error = msg.error
10
+
11
+ self.(error)
12
+ end
13
+
14
+ def call error
15
+ record_error_proc.(error)
16
+ end
17
+
18
+ def record_error_proc
19
+ @record_error_proc ||= proc { }
20
+ end
21
+ end
22
+ end
23
+ end
metadata ADDED
@@ -0,0 +1,142 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: evt-component_host
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0.0
5
+ platform: ruby
6
+ authors:
7
+ - The Eventide Project
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-05-31 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ntl-actor
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: evt-async_invocation
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: evt-casing
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :runtime
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: evt-log
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: evt-virtual
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">="
74
+ - !ruby/object:Gem::Version
75
+ version: '0'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">="
81
+ - !ruby/object:Gem::Version
82
+ version: '0'
83
+ - !ruby/object:Gem::Dependency
84
+ name: test_bench
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - ">="
88
+ - !ruby/object:Gem::Version
89
+ version: '0'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - ">="
95
+ - !ruby/object:Gem::Version
96
+ version: '0'
97
+ description: " "
98
+ email: opensource@eventide-project.org
99
+ executables: []
100
+ extensions: []
101
+ extra_rdoc_files: []
102
+ files:
103
+ - lib/component_host.rb
104
+ - lib/component_host/component_host.rb
105
+ - lib/component_host/controls.rb
106
+ - lib/component_host/controls/error.rb
107
+ - lib/component_host/controls/process_name.rb
108
+ - lib/component_host/controls/start_component.rb
109
+ - lib/component_host/controls/start_component/actor_crashes.rb
110
+ - lib/component_host/controls/start_component/raises_error.rb
111
+ - lib/component_host/controls/start_component/runs_continuously.rb
112
+ - lib/component_host/controls/start_component/stops_immediately.rb
113
+ - lib/component_host/host.rb
114
+ - lib/component_host/log.rb
115
+ - lib/component_host/signal.rb
116
+ - lib/component_host/supervisor_observers/log.rb
117
+ - lib/component_host/supervisor_observers/record_errors.rb
118
+ homepage: https://github.com/eventide-project/component-host
119
+ licenses:
120
+ - MIT
121
+ metadata: {}
122
+ post_install_message:
123
+ rdoc_options: []
124
+ require_paths:
125
+ - lib
126
+ required_ruby_version: !ruby/object:Gem::Requirement
127
+ requirements:
128
+ - - ">="
129
+ - !ruby/object:Gem::Version
130
+ version: '2.4'
131
+ required_rubygems_version: !ruby/object:Gem::Requirement
132
+ requirements:
133
+ - - ">="
134
+ - !ruby/object:Gem::Version
135
+ version: '0'
136
+ requirements: []
137
+ rubyforge_project:
138
+ rubygems_version: 2.6.11
139
+ signing_key:
140
+ specification_version: 4
141
+ summary: Host components inside a single physical process
142
+ test_files: []