evt-component_host 0.1.0.0

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 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: []