rsmp 0.8.3 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/rspec.yaml +14 -0
- data/.ruby-version +1 -1
- data/Gemfile.lock +46 -67
- data/README.md +2 -2
- data/bin/console +1 -1
- data/config/tlc.yaml +8 -6
- data/documentation/classes_and_modules.md +4 -4
- data/documentation/collecting_message.md +2 -2
- data/documentation/tasks.md +149 -0
- data/lib/rsmp/archive.rb +3 -3
- data/lib/rsmp/cli.rb +27 -4
- data/lib/rsmp/collect/aggregated_status_collector.rb +1 -1
- data/lib/rsmp/collect/collector.rb +13 -6
- data/lib/rsmp/collect/command_response_collector.rb +1 -1
- data/lib/rsmp/collect/state_collector.rb +1 -1
- data/lib/rsmp/collect/status_collector.rb +2 -1
- data/lib/rsmp/components.rb +3 -3
- data/lib/rsmp/convert/export/json_schema.rb +4 -4
- data/lib/rsmp/convert/import/yaml.rb +1 -1
- data/lib/rsmp/error.rb +0 -3
- data/lib/rsmp/inspect.rb +1 -1
- data/lib/rsmp/logger.rb +5 -5
- data/lib/rsmp/logging.rb +1 -1
- data/lib/rsmp/message.rb +1 -1
- data/lib/rsmp/node.rb +10 -45
- data/lib/rsmp/proxy.rb +184 -134
- data/lib/rsmp/rsmp.rb +1 -1
- data/lib/rsmp/site.rb +24 -61
- data/lib/rsmp/site_proxy.rb +33 -37
- data/lib/rsmp/supervisor.rb +25 -21
- data/lib/rsmp/supervisor_proxy.rb +55 -29
- data/lib/rsmp/task.rb +84 -0
- data/lib/rsmp/tlc/signal_group.rb +17 -7
- data/lib/rsmp/tlc/signal_plan.rb +2 -2
- data/lib/rsmp/tlc/traffic_controller.rb +125 -39
- data/lib/rsmp/tlc/traffic_controller_site.rb +51 -35
- data/lib/rsmp/version.rb +1 -1
- data/lib/rsmp.rb +1 -1
- data/rsmp.gemspec +7 -7
- metadata +20 -20
- data/lib/rsmp/site_proxy_wait.rb +0 -0
- data/lib/rsmp/wait.rb +0 -16
- data/test.rb +0 -27
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dde978c380def64dfcad00d0a7c9845a7c57476828623664dcf2ace7f3f6b669
|
4
|
+
data.tar.gz: 6dadc564b21089271b9921f876b95c899ad42c5bbc27b9250d34b47648447937
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7bc25b5125c599a5c46db4c919e8bf6891ddad0631de6264dfe5df97eac5cdf85768f099df8f41bff26203fb6fb15d95f4b09c8e2d4b32e80b24b3065be88d1e
|
7
|
+
data.tar.gz: 8b58da0f830cc4e4fa7f0906a2d691a3d1548b364c21e320c0f597ce4da873dd16b2db0d5e196c70f21fa9126c24a4e3f4c951586768cad0f99b78047ed7eb18
|
@@ -0,0 +1,14 @@
|
|
1
|
+
# This workflow runs RSpec tests
|
2
|
+
|
3
|
+
name: RSpec
|
4
|
+
on: [push, pull_request]
|
5
|
+
jobs:
|
6
|
+
test:
|
7
|
+
runs-on: ubuntu-latest
|
8
|
+
steps:
|
9
|
+
- uses: actions/checkout@v2
|
10
|
+
- uses: ruby/setup-ruby@v1
|
11
|
+
with:
|
12
|
+
# ruby-version is not needed because we have a .ruby-version file
|
13
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
14
|
+
- run: bundle exec rspec
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
3.0
|
1
|
+
3.1.0
|
data/Gemfile.lock
CHANGED
@@ -1,27 +1,21 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
rsmp (0.
|
4
|
+
rsmp (0.9.0)
|
5
5
|
async (~> 1.29.1)
|
6
|
-
async-io (~> 1.32.
|
6
|
+
async-io (~> 1.32.2)
|
7
7
|
colorize (~> 0.8.1)
|
8
8
|
rsmp_schemer
|
9
|
-
thor (~> 1.
|
9
|
+
thor (~> 1.2.1)
|
10
10
|
|
11
11
|
GEM
|
12
12
|
remote: https://rubygems.org/
|
13
13
|
specs:
|
14
|
-
|
15
|
-
concurrent-ruby (~> 1.0, >= 1.0.2)
|
16
|
-
i18n (>= 1.6, < 2)
|
17
|
-
minitest (>= 5.1)
|
18
|
-
tzinfo (~> 2.0)
|
19
|
-
zeitwerk (~> 2.3)
|
20
|
-
aruba (1.1.2)
|
14
|
+
aruba (2.0.0)
|
21
15
|
bundler (>= 1.17, < 3.0)
|
22
16
|
childprocess (>= 2.0, < 5.0)
|
23
17
|
contracts (>= 0.16.0, < 0.18.0)
|
24
|
-
cucumber (>=
|
18
|
+
cucumber (>= 4.0, < 8.0)
|
25
19
|
rspec-expectations (~> 3.4)
|
26
20
|
thor (~> 1.0)
|
27
21
|
async (1.29.2)
|
@@ -33,68 +27,56 @@ GEM
|
|
33
27
|
builder (3.2.4)
|
34
28
|
childprocess (4.1.0)
|
35
29
|
colorize (0.8.1)
|
36
|
-
concurrent-ruby (1.1.9)
|
37
30
|
console (1.14.0)
|
38
31
|
fiber-local
|
39
32
|
contracts (0.17)
|
40
|
-
cucumber (
|
33
|
+
cucumber (7.1.0)
|
41
34
|
builder (~> 3.2, >= 3.2.4)
|
42
|
-
cucumber-core (~>
|
43
|
-
cucumber-create-meta (~>
|
44
|
-
cucumber-cucumber-expressions (~>
|
45
|
-
cucumber-gherkin (~>
|
46
|
-
cucumber-html-formatter (~>
|
47
|
-
cucumber-messages (~>
|
48
|
-
cucumber-wire (~>
|
35
|
+
cucumber-core (~> 10.1, >= 10.1.0)
|
36
|
+
cucumber-create-meta (~> 6.0, >= 6.0.1)
|
37
|
+
cucumber-cucumber-expressions (~> 14.0, >= 14.0.0)
|
38
|
+
cucumber-gherkin (~> 22.0, >= 22.0.0)
|
39
|
+
cucumber-html-formatter (~> 17.0, >= 17.0.0)
|
40
|
+
cucumber-messages (~> 17.1, >= 17.1.1)
|
41
|
+
cucumber-wire (~> 6.2, >= 6.2.0)
|
49
42
|
diff-lcs (~> 1.4, >= 1.4.4)
|
50
43
|
mime-types (~> 3.3, >= 3.3.1)
|
51
44
|
multi_test (~> 0.1, >= 0.1.2)
|
52
45
|
sys-uname (~> 1.2, >= 1.2.2)
|
53
|
-
cucumber-core (
|
54
|
-
cucumber-gherkin (~>
|
55
|
-
cucumber-messages (~>
|
56
|
-
cucumber-tag-expressions (~>
|
57
|
-
cucumber-create-meta (
|
58
|
-
cucumber-messages (~>
|
46
|
+
cucumber-core (10.1.1)
|
47
|
+
cucumber-gherkin (~> 22.0, >= 22.0.0)
|
48
|
+
cucumber-messages (~> 17.1, >= 17.1.1)
|
49
|
+
cucumber-tag-expressions (~> 4.1, >= 4.1.0)
|
50
|
+
cucumber-create-meta (6.0.4)
|
51
|
+
cucumber-messages (~> 17.1, >= 17.1.1)
|
59
52
|
sys-uname (~> 1.2, >= 1.2.2)
|
60
|
-
cucumber-cucumber-expressions (
|
61
|
-
cucumber-gherkin (
|
62
|
-
cucumber-messages (~>
|
63
|
-
cucumber-html-formatter (
|
64
|
-
cucumber-messages (~>
|
65
|
-
cucumber-messages (
|
66
|
-
|
67
|
-
cucumber-
|
68
|
-
|
69
|
-
cucumber-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
regexp_parser (~> 2.0)
|
75
|
-
ffi (1.15.3)
|
53
|
+
cucumber-cucumber-expressions (14.0.0)
|
54
|
+
cucumber-gherkin (22.0.0)
|
55
|
+
cucumber-messages (~> 17.1, >= 17.1.1)
|
56
|
+
cucumber-html-formatter (17.0.0)
|
57
|
+
cucumber-messages (~> 17.1, >= 17.1.0)
|
58
|
+
cucumber-messages (17.1.1)
|
59
|
+
cucumber-tag-expressions (4.1.0)
|
60
|
+
cucumber-wire (6.2.1)
|
61
|
+
cucumber-core (~> 10.1, >= 10.1.0)
|
62
|
+
cucumber-cucumber-expressions (~> 14.0, >= 14.0.0)
|
63
|
+
diff-lcs (1.5.0)
|
64
|
+
ecma-re-validator (0.4.0)
|
65
|
+
regexp_parser (~> 2.2)
|
66
|
+
ffi (1.15.5)
|
76
67
|
fiber-local (1.0.0)
|
77
68
|
hana (1.3.7)
|
78
|
-
i18n (1.8.10)
|
79
|
-
concurrent-ruby (~> 1.0)
|
80
69
|
json_schemer (0.2.18)
|
81
70
|
ecma-re-validator (~> 0.3)
|
82
71
|
hana (~> 1.3)
|
83
72
|
regexp_parser (~> 2.0)
|
84
73
|
uri_template (~> 0.7)
|
85
|
-
|
86
|
-
mime-types (3.3.1)
|
74
|
+
mime-types (3.4.1)
|
87
75
|
mime-types-data (~> 3.2015)
|
88
|
-
mime-types-data (3.
|
89
|
-
minitest (5.14.4)
|
76
|
+
mime-types-data (3.2022.0105)
|
90
77
|
multi_test (0.1.2)
|
91
78
|
nio4r (2.5.8)
|
92
|
-
|
93
|
-
activesupport (>= 3.2)
|
94
|
-
middleware
|
95
|
-
thor
|
96
|
-
thread_safe
|
97
|
-
rake (13.0.3)
|
79
|
+
rake (13.0.6)
|
98
80
|
regexp_parser (2.2.0)
|
99
81
|
rsmp_schemer (0.3.2)
|
100
82
|
json_schemer (~> 0.2.18)
|
@@ -104,37 +86,34 @@ GEM
|
|
104
86
|
rspec-mocks (~> 3.10.0)
|
105
87
|
rspec-core (3.10.1)
|
106
88
|
rspec-support (~> 3.10.0)
|
107
|
-
rspec-expectations (3.10.
|
89
|
+
rspec-expectations (3.10.2)
|
108
90
|
diff-lcs (>= 1.2.0, < 2.0)
|
109
91
|
rspec-support (~> 3.10.0)
|
110
92
|
rspec-mocks (3.10.2)
|
111
93
|
diff-lcs (>= 1.2.0, < 2.0)
|
112
94
|
rspec-support (~> 3.10.0)
|
113
|
-
rspec-support (3.10.
|
95
|
+
rspec-support (3.10.3)
|
114
96
|
sys-uname (1.2.2)
|
115
97
|
ffi (~> 1.1)
|
116
|
-
thor (1.
|
117
|
-
thread_safe (0.3.6)
|
98
|
+
thor (1.2.1)
|
118
99
|
timecop (0.9.4)
|
119
100
|
timers (4.3.3)
|
120
|
-
tzinfo (2.0.4)
|
121
|
-
concurrent-ruby (~> 1.0)
|
122
101
|
uri_template (0.7.0)
|
123
|
-
zeitwerk (2.4.2)
|
124
102
|
|
125
103
|
PLATFORMS
|
126
104
|
x86_64-darwin-20
|
127
105
|
x86_64-darwin-21
|
106
|
+
x86_64-linux
|
128
107
|
|
129
108
|
DEPENDENCIES
|
130
|
-
aruba (~>
|
131
|
-
bundler (~> 2.
|
132
|
-
cucumber (~>
|
133
|
-
rake (~> 13.0.
|
109
|
+
aruba (~> 2.0.0)
|
110
|
+
bundler (~> 2.3.6)
|
111
|
+
cucumber (~> 7.1.0)
|
112
|
+
rake (~> 13.0.6)
|
134
113
|
rsmp!
|
135
114
|
rspec (~> 3.10.0)
|
136
|
-
rspec-expectations (~> 3.10.
|
115
|
+
rspec-expectations (~> 3.10.2)
|
137
116
|
timecop (~> 0.9.4)
|
138
117
|
|
139
118
|
BUNDLED WITH
|
140
|
-
2.
|
119
|
+
2.3.6
|
data/README.md
CHANGED
@@ -23,7 +23,7 @@ $ git submodule update # fetch submodules
|
|
23
23
|
|
24
24
|
Alternatively, you can pass --recurse-submodules to the git clone command, and it will automatically initialize and update each submodule in the repository.
|
25
25
|
|
26
|
-
## Usage
|
26
|
+
## Usage
|
27
27
|
### Site and Supervisor
|
28
28
|
The RSMP::Site and RSMP::Supervisor classes can be used to run a RSMP site.
|
29
29
|
|
@@ -172,7 +172,7 @@ Use the ```tlc``` site type to run an emulation of a traffic light controller. T
|
|
172
172
|
### CLI help and options.
|
173
173
|
Use ```--help <command>``` to get a list of available options.
|
174
174
|
|
175
|
-
Use ```--config <path>``` to point to a .yaml config file, controlling things like IP adresses, ports, and log output. Examples of config files can be found the folder ```config/```.
|
175
|
+
Use ```--config <path>``` to point to a .yaml config file, controlling things like IP adresses, ports, and log output. Examples of config files can be found the folder ```config/```.
|
176
176
|
|
177
177
|
## Tests
|
178
178
|
### RSpec
|
data/bin/console
CHANGED
data/config/tlc.yaml
CHANGED
@@ -20,17 +20,18 @@ signal_plans:
|
|
20
20
|
dynamic_bands:
|
21
21
|
1: 0
|
22
22
|
2: 5
|
23
|
-
states:
|
24
|
-
A1: '123efg'
|
25
|
-
A2: '123efg'
|
26
|
-
B1: '123efg'
|
27
|
-
B2: '123efg'
|
28
|
-
2:
|
29
23
|
states:
|
30
24
|
A1: '111NBB'
|
31
25
|
A2: '11NBBB'
|
32
26
|
B1: 'BBB11N'
|
33
27
|
B2: 'BBB1NB'
|
28
|
+
2:
|
29
|
+
states:
|
30
|
+
A1: 'NNNNBB'
|
31
|
+
A2: 'NNNNBN'
|
32
|
+
B1: 'BBNNNN'
|
33
|
+
B2: 'BNNNNN'
|
34
|
+
startup_sequence: 'efg'
|
34
35
|
intervals:
|
35
36
|
timer: 0.1
|
36
37
|
watchdog: 0.1
|
@@ -48,3 +49,4 @@ log:
|
|
48
49
|
level: false
|
49
50
|
debug: true
|
50
51
|
json: true
|
52
|
+
live_output: tmp/tlc.state
|
@@ -14,13 +14,13 @@ SupervisorProxy SiteProxy - - include Components, SiteProxyWait
|
|
14
14
|
|
15
15
|
## Modules
|
16
16
|
### Logging
|
17
|
-
|
17
|
+
Handles logging.
|
18
18
|
|
19
|
-
###
|
20
|
-
Handles
|
19
|
+
### Task
|
20
|
+
Handles async tasks.
|
21
21
|
|
22
22
|
### Components
|
23
|
-
|
23
|
+
Handles RSMP components.
|
24
24
|
|
25
25
|
## Classes
|
26
26
|
### Node
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# Collection
|
2
2
|
You often need to collect messages or responses. The collector classes are used to collect message asyncronously. Other tasks continue until the collection completes, time outs or is cancelled.
|
3
3
|
|
4
|
-
A collector can collect ingoing and/or outgoing messages.
|
4
|
+
A collector can collect ingoing and/or outgoing messages.
|
5
5
|
|
6
6
|
An object that includes the Notifier module (or implements the same functionality) must be provided when you construct a Collected. The collector will attach itself to this notifier when it starts collecting, to receive messages. The SiteProxy and SupervisorProxy classes both include the Notifier module, and can therefore be used as message sources.
|
7
7
|
|
@@ -32,7 +32,7 @@ outgoing: Whether to collect outgoing messages. Defaults to true
|
|
32
32
|
component: An RSMP component id.
|
33
33
|
|
34
34
|
### Collecting
|
35
|
-
Use collect() to start collecting and wait for completion or timeout. The status will be returned.
|
35
|
+
Use collect() to start collecting and wait for completion or timeout. The status will be returned.
|
36
36
|
|
37
37
|
```ruby
|
38
38
|
result = collector.collect # => :ok, :timeout or :cancelled
|
@@ -0,0 +1,149 @@
|
|
1
|
+
# Tasks
|
2
|
+
|
3
|
+
## Concurrency
|
4
|
+
When you use a site or a supervisor, it runs asyncronously so you can run several concurrently, or do other things concurrently, like sending messages and waiting for reponses.
|
5
|
+
|
6
|
+
Concurrency is provided by Ruby Fiber Scheduler and the Async gem. and used to:
|
7
|
+
|
8
|
+
- Runn multiple sites or supervisors
|
9
|
+
- Run multiple connections from each site or supervisor
|
10
|
+
- Wait for messages, connections or states
|
11
|
+
|
12
|
+
Classes don't inherit from Async::Task. Instead they include task as instance variables. This means that the hierachy of objects and tasks can be different.
|
13
|
+
|
14
|
+
## Task module
|
15
|
+
The `Task` module is used by the `Node` and `Proxy` classes and defines a life cycle for handling async tasks.
|
16
|
+
|
17
|
+
A single main tasks is kept in `@task`. If subclasses need subtask, they can start them as needed, inside the main task.
|
18
|
+
|
19
|
+
You first call `start`. If `@task` already exists, it will return immedatiately.
|
20
|
+
Otherwise an async task is created and stored in `@task`, and `run` is called inside this task, to handle any long-running jobs, like listening for incoming messages. By default `run` calls `start_subtasks`, but should be overriden to do actual work as well.
|
21
|
+
The call to `start` returns immediately, with the async task running concurently.
|
22
|
+
|
23
|
+
If you want to stop the task, call `stop`. It will fist call `stop_subtasks` and then `stop_task` which calls Async#stop on `@task` and sets `@task` to `nil`.
|
24
|
+
|
25
|
+
## Stopping tasks
|
26
|
+
If a task stops itself, code after the call to `stop` will not be run, unless you use an ensure block:
|
27
|
+
|
28
|
+
```ruby
|
29
|
+
require 'async'
|
30
|
+
|
31
|
+
Async do |task|
|
32
|
+
task.stop
|
33
|
+
puts "I just stopped" # this will not be reaced, because the task was stopped
|
34
|
+
end
|
35
|
+
|
36
|
+
Async do |task|
|
37
|
+
task.stop
|
38
|
+
ensure
|
39
|
+
puts "I just stopped" # this will be reached
|
40
|
+
end
|
41
|
+
```
|
42
|
+
This can happen if either the task stops itself directly, or if it stops task higher up in the task hierarchy.
|
43
|
+
|
44
|
+
For example, when a timer task finds that an acknowledgement was not received in time, and then closes the connection by calling stop() on the Proxy, the proxy which will then in turn stop the timer task. So any code that should be run after that must be inside an ensure block.
|
45
|
+
|
46
|
+
## Proxies
|
47
|
+
A site connects to one of more supervisors. A proxy is created and run to handle each connection.
|
48
|
+
|
49
|
+
A site can connect to one or more supervisor. It creates a proxy for each and runs them.
|
50
|
+
|
51
|
+
When the proxy is run, it creates an async task to read incoming messages. This reader task is stored in `@reader`and will be a sub task of the site/supervisor main task.
|
52
|
+
|
53
|
+
A proxy also creates a timer task, stored in `@timer`. This task is used to check watchdog and acknowledgement timeouts.
|
54
|
+
|
55
|
+
Proxies build on the Task module functionality by handling RSMP communication via a TCP socket.
|
56
|
+
|
57
|
+
The TCP socket can be open or closed. The RSMP communication first goes through a handshake sequence before being ready. The `status` attribute keeps track of this, and can be either `:disconnected`, `:connected` or `:ready`
|
58
|
+
|
59
|
+
Proxies provide `connect` and `close` for starting and stopping commununication.
|
60
|
+
|
61
|
+
A supervisor proxies connects actively to a site proxy, whereas a site proxy waits for the supervisor proxy to connect.
|
62
|
+
|
63
|
+
A supervisor proxy is created at startup, and is responsible for creating the TCP socket and connecting to the supervisor.
|
64
|
+
|
65
|
+
A site proxy is also created at startup, but the socket is created in the supervisor by `Aync::Endpoint#accept`when a site connects.
|
66
|
+
|
67
|
+
## Object Hierarchy
|
68
|
+
A Site has one or more SupervisorProxies, which represent connections to the remote supervisor.
|
69
|
+
|
70
|
+
A Supervisor has one or more SiteProxies, which represent connections to the remote site.
|
71
|
+
|
72
|
+
SiteProxy and SupervisorProxy both inherit from Proxy and have a reader task and a timer task. These are just Async tasks, not separate classes.
|
73
|
+
|
74
|
+
## Task Hierachy
|
75
|
+
When you start an Async task, the parent will be the currently running task, unless you specify a different parent task.
|
76
|
+
|
77
|
+
The Async task hierarchy is similar to the object hierachy, with the difference that proxies have reader and timer tasks. And Async::IO which is used to handle TPC connections concurently, will create some intermediate tasks:
|
78
|
+
|
79
|
+
```
|
80
|
+
Supervisor @task
|
81
|
+
accepting connections # this task is created by Async::IO
|
82
|
+
incoming connection 1 # this task is created by Async::IO
|
83
|
+
SiteProxy @task
|
84
|
+
SiteProxy @reader
|
85
|
+
SiteProxy @timer
|
86
|
+
incoming connection 2 # this task is created by Async::IO
|
87
|
+
SiteProxy @task
|
88
|
+
SiteProxy @reader
|
89
|
+
SiteProxy @timer
|
90
|
+
|
91
|
+
```
|
92
|
+
|
93
|
+
|
94
|
+
A Site run from the CLI, before it connects to a supervisor:
|
95
|
+
|
96
|
+
```
|
97
|
+
#<Async::Reactor:0xb90 1 children (running)>
|
98
|
+
#<Async::Task:0xba4 cli (running)>
|
99
|
+
#<Async::Task:0xbcc RSMP::TLC::TrafficControllerSite main task (running)>
|
100
|
+
#<Async::Task:0xbe0 RSMP::SupervisorProxy main task (running)>
|
101
|
+
#<Async::Task:0xbf4 tlc timer (running)>
|
102
|
+
```
|
103
|
+
|
104
|
+
After the site connects to a supervisor:
|
105
|
+
|
106
|
+
```
|
107
|
+
#<Async::Reactor:0xadc 1 children (running)>
|
108
|
+
#<Async::Task:0xaf0 cli (running)>
|
109
|
+
#<Async::Task:0xb18 RSMP::TLC::TrafficControllerSite main task (running)>
|
110
|
+
#<Async::Task:0xb2c RSMP::SupervisorProxy main task (running)>
|
111
|
+
#<Async::Task:0xb40 reader (running)>
|
112
|
+
#<Async::Task:0xb54 timer (running)>
|
113
|
+
#<Async::Task:0xb68 tlc timer (running)>
|
114
|
+
```
|
115
|
+
|
116
|
+
|
117
|
+
|
118
|
+
A supervisor run from the CLI, before any sites have connected:
|
119
|
+
|
120
|
+
```
|
121
|
+
#<Async::Reactor:0x94c 1 children (running)>
|
122
|
+
#<Async::Task:0x960 cli (running)>
|
123
|
+
#<Async::Task:0x988 RSMP::Supervisor main task (running)>
|
124
|
+
#<Async::Task:0x99c accepting connections #<Addrinfo: 0.0.0.0:14111 TCP> [fd=12] (running)>
|
125
|
+
```
|
126
|
+
|
127
|
+
The supervisor after a site has connected
|
128
|
+
|
129
|
+
```
|
130
|
+
#<Async::Reactor:0x94c 1 children (running)>
|
131
|
+
#<Async::Task:0x960 cli (running)>
|
132
|
+
#<Async::Task:0x988 RSMP::Supervisor main task (running)>
|
133
|
+
#<Async::Task:0x99c accepting connections #<Addrinfo: 0.0.0.0:13111 TCP> [fd=12] (running)>
|
134
|
+
#<Async::Task:0xac8 incoming connection #<Addrinfo: 127.0.0.1:51778 TCP> [fd=13] (running)>
|
135
|
+
#<Async::Task:0xadc RSMP::SiteProxy main task (running)>
|
136
|
+
#<Async::Task:0xaf0 reader (running)>
|
137
|
+
#<Async::Task:0xb04 timer (running)>
|
138
|
+
```
|
139
|
+
|
140
|
+
The task hierachy matters when you stop a task or iterate on subtasks. Note that calling `Task#wait`
|
141
|
+
does not wait for subtasks, whereas Task#stop stops all subtasks.
|
142
|
+
|
143
|
+
## Transient tasks
|
144
|
+
If you mark an Async task with `transient: true` when you created it, that task will be stopped aas soon as all normal task are completed. They will also be moved up the hierarchy if the parent is complete, but not the grandparent.
|
145
|
+
|
146
|
+
Transient tasks can be used to cleanup, but using an `ensure` block in the transient task. When you call `stop` on a task, an Async::Stop exception is raised, which will run the code in the `ensure` block.
|
147
|
+
|
148
|
+
Some of the RSpec tests runs tests in in transient task. As soon as the main test code is complete, any subtasks like Sites or Supervisors that might otherwise prevent the test from completing, will be stopped automatically.
|
149
|
+
|
data/lib/rsmp/archive.rb
CHANGED
@@ -20,11 +20,11 @@ module RSMP
|
|
20
20
|
|
21
21
|
def self.prepare_item item
|
22
22
|
raise ArgumentError unless item.is_a? Hash
|
23
|
-
|
23
|
+
|
24
24
|
cleaned = item.select { |k,v| [:author,:level,:ip,:port,:site_id,:component,:text,:message,:exception].include? k }
|
25
25
|
cleaned[:timestamp] = Clock.now
|
26
26
|
if item[:message]
|
27
|
-
cleaned[:direction] = item[:message].direction
|
27
|
+
cleaned[:direction] = item[:message].direction
|
28
28
|
cleaned[:component] = item[:message].attributes['cId']
|
29
29
|
end
|
30
30
|
|
@@ -54,7 +54,7 @@ module RSMP
|
|
54
54
|
@items.shift
|
55
55
|
end
|
56
56
|
end
|
57
|
-
|
57
|
+
|
58
58
|
private
|
59
59
|
|
60
60
|
def find options, &block
|
data/lib/rsmp/cli.rb
CHANGED
@@ -11,7 +11,7 @@ module RSMP
|
|
11
11
|
desc "site", "Run RSMP site"
|
12
12
|
method_option :config, :type => :string, :aliases => "-c", banner: 'Path to .yaml config file'
|
13
13
|
method_option :id, :type => :string, :aliases => "-i", banner: 'RSMP site id'
|
14
|
-
method_option :supervisors, :type => :string, :aliases => "-s", banner: 'ip:port,... list of supervisor to connect to'
|
14
|
+
method_option :supervisors, :type => :string, :aliases => "-s", banner: 'ip:port,... list of supervisor to connect to'
|
15
15
|
method_option :log, :type => :string, :aliases => "-l", banner: 'Path to log file'
|
16
16
|
method_option :json, :type => :boolean, :aliases => "-j", banner: 'Show JSON messages in log'
|
17
17
|
method_option :type, :type => :string, :aliases => "-t", banner: 'Type of site: [tlc]'
|
@@ -60,19 +60,35 @@ module RSMP
|
|
60
60
|
site_class = RSMP::Site
|
61
61
|
end
|
62
62
|
end
|
63
|
-
|
63
|
+
Async do |task|
|
64
|
+
task.annotate 'cli'
|
65
|
+
loop do
|
66
|
+
begin
|
67
|
+
site = site_class.new(site_settings:settings, log_settings: log_settings)
|
68
|
+
site.start
|
69
|
+
site.wait
|
70
|
+
rescue RSMP::Restart
|
71
|
+
site.stop
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
rescue Interrupt
|
76
|
+
# cntr-c
|
64
77
|
rescue RSMP::Schemer::UnknownSchemaTypeError => e
|
65
78
|
puts "Cannot start site: #{e}"
|
66
79
|
rescue RSMP::Schemer::UnknownSchemaVersionError => e
|
67
80
|
puts "Cannot start site: #{e}"
|
68
81
|
rescue Psych::SyntaxError => e
|
69
82
|
puts "Cannot read config file #{e}"
|
83
|
+
rescue Exception => e
|
84
|
+
puts "Uncaught error: #{e}"
|
85
|
+
puts caller.join("\n")
|
70
86
|
end
|
71
87
|
|
72
88
|
desc "supervisor", "Run RSMP supervisor"
|
73
89
|
method_option :config, :type => :string, :aliases => "-c", banner: 'Path to .yaml config file'
|
74
90
|
method_option :id, :type => :string, :aliases => "-i", banner: 'RSMP site id'
|
75
|
-
method_option :ip, :type => :numeric, banner: 'IP address to listen on'
|
91
|
+
method_option :ip, :type => :numeric, banner: 'IP address to listen on'
|
76
92
|
method_option :port, :type => :string, :aliases => "-p", banner: 'Port to listen on'
|
77
93
|
method_option :log, :type => :string, :aliases => "-l", banner: 'Path to log file'
|
78
94
|
method_option :json, :type => :boolean, :aliases => "-j", banner: 'Show JSON messages in log'
|
@@ -110,7 +126,14 @@ module RSMP
|
|
110
126
|
log_settings['json'] = options[:json]
|
111
127
|
end
|
112
128
|
|
113
|
-
|
129
|
+
Async do |task|
|
130
|
+
task.annotate 'cli'
|
131
|
+
supervisor = RSMP::Supervisor.new(supervisor_settings:settings,log_settings:log_settings)
|
132
|
+
supervisor.start
|
133
|
+
supervisor.wait
|
134
|
+
end
|
135
|
+
rescue Interrupt
|
136
|
+
# ctrl-c
|
114
137
|
rescue RSMP::ConfigurationError => e
|
115
138
|
puts "Cannot start supervisor: #{e}"
|
116
139
|
end
|
@@ -2,7 +2,7 @@ module RSMP
|
|
2
2
|
# Class for waiting for an aggregated status response
|
3
3
|
class AggregatedStatusCollector < Collector
|
4
4
|
def initialize proxy, options={}
|
5
|
-
required = { type:
|
5
|
+
required = { type: 'AggregatedStatus', title: 'aggregated status' }
|
6
6
|
super proxy, options.merge(required)
|
7
7
|
end
|
8
8
|
end
|
@@ -51,12 +51,12 @@ module RSMP
|
|
51
51
|
@status == :collecting
|
52
52
|
end
|
53
53
|
|
54
|
-
# Is collection
|
54
|
+
# Is collection complete?
|
55
55
|
def ok?
|
56
56
|
@status == :ok
|
57
57
|
end
|
58
58
|
|
59
|
-
# Has collection
|
59
|
+
# Has collection timed out?
|
60
60
|
def timeout?
|
61
61
|
@status == :timeout
|
62
62
|
end
|
@@ -81,6 +81,13 @@ module RSMP
|
|
81
81
|
@outgoing == true
|
82
82
|
end
|
83
83
|
|
84
|
+
# if an errors caused collection to abort, then raise it
|
85
|
+
# return self, so this can be tucked on to calls that return a collector
|
86
|
+
def ok!
|
87
|
+
raise @error if @error
|
88
|
+
self
|
89
|
+
end
|
90
|
+
|
84
91
|
# Collect message
|
85
92
|
# Will return once all messages have been collected, or timeout is reached
|
86
93
|
def collect &block
|
@@ -94,9 +101,8 @@ module RSMP
|
|
94
101
|
# Collect message
|
95
102
|
# Returns the collected messages, or raise an exception in case of a time out.
|
96
103
|
def collect! &block
|
97
|
-
|
98
|
-
|
99
|
-
end
|
104
|
+
collect(&block)
|
105
|
+
ok!
|
100
106
|
@messages
|
101
107
|
end
|
102
108
|
|
@@ -112,6 +118,7 @@ module RSMP
|
|
112
118
|
end
|
113
119
|
@status
|
114
120
|
rescue Async::TimeoutError
|
121
|
+
@error = RSMP::TimeoutError.new describe_progress
|
115
122
|
@status = :timeout
|
116
123
|
end
|
117
124
|
|
@@ -120,7 +127,7 @@ module RSMP
|
|
120
127
|
# If timeout is reached, an exceptioin is raised.
|
121
128
|
def wait!
|
122
129
|
wait
|
123
|
-
raise
|
130
|
+
raise @error if timeout?
|
124
131
|
@messages
|
125
132
|
end
|
126
133
|
|
@@ -2,8 +2,9 @@ module RSMP
|
|
2
2
|
# Base class for waiting for status updates or responses
|
3
3
|
class StatusCollector < StateCollector
|
4
4
|
def initialize proxy, want, options={}
|
5
|
-
super proxy, want, options.merge(title: 'status response'
|
5
|
+
super proxy, want, options.merge(title: 'status response')
|
6
6
|
|
7
|
+
@options[:type] ||= []
|
7
8
|
@options[:type] << 'StatusUpdate' unless options[:updates] == false
|
8
9
|
@options[:type] << 'StatusResponse' unless options[:reponses] == false
|
9
10
|
end
|
data/lib/rsmp/components.rb
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
module RSMP
|
4
4
|
module Components
|
5
5
|
attr_reader :components
|
6
|
-
|
6
|
+
|
7
7
|
def initialize_components
|
8
8
|
@components = {}
|
9
9
|
end
|
@@ -25,10 +25,10 @@ module RSMP
|
|
25
25
|
|
26
26
|
def check_main_component settings
|
27
27
|
unless settings['main'] && settings['main'].size >= 1
|
28
|
-
raise ConfigurationError.new("main component must be defined")
|
28
|
+
raise ConfigurationError.new("main component must be defined")
|
29
29
|
end
|
30
30
|
if settings['main'].size > 1
|
31
|
-
raise ConfigurationError.new("only one main component can be defined, found #{settings['main'].keys.join(', ')}")
|
31
|
+
raise ConfigurationError.new("only one main component can be defined, found #{settings['main'].keys.join(', ')}")
|
32
32
|
end
|
33
33
|
end
|
34
34
|
|