evt-process_host 0.4.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 923259786e0921de59f0cac14e21764530396d08
4
+ data.tar.gz: 641f3df3fe348e387d6b00ef7b15e547d4314079
5
+ SHA512:
6
+ metadata.gz: eaa183daea5d2adc9e1e8001e136a71c16efda922ebd3b7dd16392419db21de7272804ec7e6b7694d1d4adf201dc63b72fe76c5dc1ec780dfcd0160ce3f60c61
7
+ data.tar.gz: 7d246d999ebc88db94fac3afdd38685ee4cfada4f07110803d9a1ec030c50921e99e4a288bda7f8c3ffc87fc5158be4b8ade0dd1ef3253b4db2b3b2a563721c6
@@ -0,0 +1,16 @@
1
+ require 'actor'
2
+ require 'async_invocation'
3
+ require 'casing'
4
+ require 'log'
5
+ require 'virtual'
6
+
7
+ require 'process_host/log'
8
+ require 'process_host/signal'
9
+
10
+ require 'process_host/host'
11
+ require 'process_host/process'
12
+ require 'process_host/process/process_name'
13
+ require 'process_host/supervisor_observers/log'
14
+ require 'process_host/supervisor_observers/record_errors'
15
+
16
+ require 'process_host/process_host'
@@ -0,0 +1,7 @@
1
+ require 'process_host/controls/component_name'
2
+ require 'process_host/controls/error'
3
+ require 'process_host/controls/process'
4
+ require 'process_host/controls/process/actor_crashes'
5
+ require 'process_host/controls/process/raises_error'
6
+ require 'process_host/controls/process/runs_continuously'
7
+ require 'process_host/controls/process/stops_immediately'
@@ -0,0 +1,9 @@
1
+ module ProcessHost
2
+ module Controls
3
+ module ComponentName
4
+ def self.example
5
+ 'some-component'
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ module ProcessHost
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,33 @@
1
+ module ProcessHost
2
+ module Controls
3
+ module Process
4
+ def self.example
5
+ Example.new
6
+ end
7
+
8
+ module Name
9
+ def self.example
10
+ :example_process
11
+ end
12
+ end
13
+
14
+ class Example
15
+ include ProcessHost::Process
16
+
17
+ process_name Name.example
18
+
19
+ attr_accessor :started
20
+
21
+ def start
22
+ self.started = true
23
+ end
24
+
25
+ module Assertions
26
+ def started?
27
+ started ? true : false
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,29 @@
1
+ module ProcessHost
2
+ module Controls
3
+ module Process
4
+ class ActorCrashes
5
+ include ProcessHost::Process
6
+
7
+ def start
8
+ Actor.start
9
+ end
10
+
11
+ def self.error
12
+ @error ||= Error.example
13
+ end
14
+
15
+ class Actor
16
+ include ::Actor
17
+
18
+ handle :start do
19
+ raise error
20
+ end
21
+
22
+ def error
23
+ ActorCrashes.error
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,21 @@
1
+ module ProcessHost
2
+ module Controls
3
+ module Process
4
+ class RaisesError
5
+ include ProcessHost::Process
6
+
7
+ def start
8
+ raise error
9
+ end
10
+
11
+ def error
12
+ self.class.error
13
+ end
14
+
15
+ def self.error
16
+ @error ||= Error.example
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,42 @@
1
+ module ProcessHost
2
+ module Controls
3
+ module Process
4
+ class RunsContinuously
5
+ include ProcessHost::Process
6
+
7
+ def start
8
+ Actor.start
9
+ end
10
+
11
+ class Actor
12
+ include ::Actor
13
+ include ::Log::Dependency
14
+
15
+ attr_writer :counter
16
+
17
+ handle :start do
18
+ :print_heartbeat
19
+ end
20
+
21
+ handle :print_heartbeat do
22
+ logger.info "Heartbeat (Counter: #{counter})"
23
+
24
+ :next
25
+ end
26
+
27
+ handle :next do
28
+ self.counter += 1
29
+
30
+ sleep 1
31
+
32
+ :print_heartbeat
33
+ end
34
+
35
+ def counter
36
+ @counter ||= 0
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,21 @@
1
+ module ProcessHost
2
+ module Controls
3
+ module Process
4
+ class StopsImmediately
5
+ include ProcessHost::Process
6
+
7
+ def start
8
+ Actor.start
9
+ end
10
+
11
+ class Actor
12
+ include ::Actor
13
+
14
+ handle :start do
15
+ :stop
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,119 @@
1
+ module ProcessHost
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(process_class, process_name=nil)
16
+ logger.trace { "Registering process (ProcessClass: #{process_class}, Name: #{process_name.inspect})" }
17
+
18
+ process_name ||= process_class.process_name
19
+
20
+ if registered_process = processes[process_name]
21
+ error_message = "Process with specified name is already registered (ProcessClass: #{process_class}, Name: #{process_name.inspect}, RegisteredProcessClass: #{registered_process.name})"
22
+
23
+ logger.error error_message
24
+
25
+ raise NameConflictError, error_message
26
+ else
27
+ processes[process_name] = process_class
28
+ end
29
+
30
+ logger.debug { "Process registered (ProcessClass: #{process_class}, Name: #{process_name.inspect})" }
31
+
32
+ process_name
33
+ end
34
+
35
+ def record_error(&block)
36
+ record_errors_observer.record_error_proc = block
37
+ end
38
+
39
+ def start(&block)
40
+ started_processes = []
41
+
42
+ Actor::Supervisor.start do |supervisor|
43
+ supervisor.add_observer record_errors_observer
44
+
45
+ supervisor.add_observer log_observer
46
+
47
+ signal.trap 'TSTP' do
48
+ message = Actor::Messages::Suspend
49
+
50
+ send.(message, supervisor.address)
51
+
52
+ logger.info { "Handled TSTP signal (MessageName: #{message.message_name}, SupervisorAddress: #{supervisor.address.id})" }
53
+ end
54
+
55
+ signal.trap 'CONT' do
56
+ message = Actor::Messages::Resume
57
+
58
+ send.(message, supervisor.address)
59
+
60
+ logger.info { "Handled CONT signal (MessageName: #{message.message_name}, SupervisorAddress: #{supervisor.address.id})" }
61
+ end
62
+
63
+ signal.trap 'INT' do
64
+ message = Actor::Messages::Shutdown
65
+
66
+ send.(message, supervisor.address)
67
+
68
+ logger.info { "Handled INT signal (MessageName: #{message.message_name}, SupervisorAddress: #{supervisor.address.id})" }
69
+ end
70
+
71
+ start_processes do |process|
72
+ started_processes << process
73
+ end
74
+
75
+ block.(supervisor) if block
76
+ end
77
+
78
+ started_processes
79
+ end
80
+
81
+ def start_processes(&block)
82
+ processes.each_value do |process_class|
83
+ process = process_class.build
84
+
85
+ process.start
86
+
87
+ block.(process) if block
88
+ end
89
+
90
+ rescue => error
91
+ record_errors_observer.(error)
92
+ raise error
93
+ end
94
+
95
+ def record_errors_observer
96
+ @record_errors_observer ||= SupervisorObservers::RecordErrors.new
97
+ end
98
+
99
+ def log_observer
100
+ @log_observer ||= SupervisorObservers::Log.new
101
+ end
102
+
103
+ def processes
104
+ @processes ||= {}
105
+ end
106
+
107
+ NameConflictError = Class.new StandardError
108
+
109
+ module Assertions
110
+ def registered?(&block)
111
+ return processes.any? if block.nil?
112
+
113
+ processes.any? do |name, process_class|
114
+ block.(process_class, name)
115
+ end
116
+ end
117
+ end
118
+ end
119
+ end
@@ -0,0 +1,8 @@
1
+ module ProcessHost
2
+ class Log < Log
3
+ def tag!(tags)
4
+ tags << :process_host
5
+ tags << :verbose
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,37 @@
1
+ module ProcessHost
2
+ module Process
3
+ def self.included(cls)
4
+ cls.class_exec do
5
+ include Log::Dependency
6
+
7
+ extend Build
8
+ extend ProcessName
9
+ prepend Start
10
+
11
+ dependency :send, Actor::Messaging::Send
12
+ end
13
+ end
14
+
15
+ Virtual::PureMethod.define self, :start
16
+
17
+ module Start
18
+ def start
19
+ logger.trace { "Starting process (ProcessName: #{self.class.process_name})" }
20
+
21
+ super
22
+
23
+ logger.debug { "Process started (ProcessName: #{self.class.process_name})" }
24
+
25
+ AsyncInvocation::Incorrect
26
+ end
27
+ end
28
+
29
+ module Build
30
+ def build
31
+ instance = new
32
+ instance.send = Actor::Messaging::Send.new
33
+ instance
34
+ end
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,41 @@
1
+ module ProcessHost
2
+ module Process
3
+ module ProcessName
4
+ def self.extended(cls)
5
+ cls.singleton_class.class_exec do
6
+ attr_writer :process_name
7
+ end
8
+ end
9
+
10
+ def process_name_macro(name)
11
+ self.process_name = name
12
+ end
13
+
14
+ def process_name(name=nil)
15
+ if name.nil?
16
+ @process_name ||= Default.get self
17
+ else
18
+ process_name_macro name
19
+ end
20
+ end
21
+
22
+ module Default
23
+ def self.get(mod)
24
+ constant_name = mod.name
25
+
26
+ return unknown if constant_name.nil?
27
+
28
+ *, constant_name = constant_name.split '::'
29
+
30
+ constant_name = Casing::Underscore.(constant_name)
31
+
32
+ constant_name.to_sym
33
+ end
34
+
35
+ def self.unknown
36
+ :unknown
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,13 @@
1
+ module ProcessHost
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,53 @@
1
+ module ProcessHost
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 ProcessHost
2
+ module SupervisorObservers
3
+ class Log
4
+ include Actor::Supervisor::Observer
5
+ include ProcessHost::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 ProcessHost
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,144 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: evt-process_host
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.0.1
5
+ platform: ruby
6
+ authors:
7
+ - The Eventide Project
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-12-22 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: evt-async_invocation
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-casing
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-log
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-virtual
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: ntl-actor
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/process_host.rb
104
+ - lib/process_host/controls.rb
105
+ - lib/process_host/controls/component_name.rb
106
+ - lib/process_host/controls/error.rb
107
+ - lib/process_host/controls/process.rb
108
+ - lib/process_host/controls/process/actor_crashes.rb
109
+ - lib/process_host/controls/process/raises_error.rb
110
+ - lib/process_host/controls/process/runs_continuously.rb
111
+ - lib/process_host/controls/process/stops_immediately.rb
112
+ - lib/process_host/host.rb
113
+ - lib/process_host/log.rb
114
+ - lib/process_host/process.rb
115
+ - lib/process_host/process/process_name.rb
116
+ - lib/process_host/process_host.rb
117
+ - lib/process_host/signal.rb
118
+ - lib/process_host/supervisor_observers/log.rb
119
+ - lib/process_host/supervisor_observers/record_errors.rb
120
+ homepage: https://github.com/eventide-project/process-host
121
+ licenses:
122
+ - MIT
123
+ metadata: {}
124
+ post_install_message:
125
+ rdoc_options: []
126
+ require_paths:
127
+ - lib
128
+ required_ruby_version: !ruby/object:Gem::Requirement
129
+ requirements:
130
+ - - ">="
131
+ - !ruby/object:Gem::Version
132
+ version: 2.3.3
133
+ required_rubygems_version: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ requirements: []
139
+ rubyforge_project:
140
+ rubygems_version: 2.6.8
141
+ signing_key:
142
+ specification_version: 4
143
+ summary: Run multiple logical processes inside a single physical process
144
+ test_files: []