rsmp 0.8.3 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/rspec.yaml +14 -0
  3. data/.ruby-version +1 -1
  4. data/Gemfile.lock +46 -67
  5. data/README.md +2 -2
  6. data/bin/console +1 -1
  7. data/config/tlc.yaml +8 -6
  8. data/documentation/classes_and_modules.md +4 -4
  9. data/documentation/collecting_message.md +2 -2
  10. data/documentation/tasks.md +149 -0
  11. data/lib/rsmp/archive.rb +3 -3
  12. data/lib/rsmp/cli.rb +27 -4
  13. data/lib/rsmp/collect/aggregated_status_collector.rb +1 -1
  14. data/lib/rsmp/collect/collector.rb +13 -6
  15. data/lib/rsmp/collect/command_response_collector.rb +1 -1
  16. data/lib/rsmp/collect/state_collector.rb +1 -1
  17. data/lib/rsmp/collect/status_collector.rb +2 -1
  18. data/lib/rsmp/components.rb +3 -3
  19. data/lib/rsmp/convert/export/json_schema.rb +4 -4
  20. data/lib/rsmp/convert/import/yaml.rb +1 -1
  21. data/lib/rsmp/error.rb +0 -3
  22. data/lib/rsmp/inspect.rb +1 -1
  23. data/lib/rsmp/logger.rb +5 -5
  24. data/lib/rsmp/logging.rb +1 -1
  25. data/lib/rsmp/message.rb +1 -1
  26. data/lib/rsmp/node.rb +10 -45
  27. data/lib/rsmp/proxy.rb +184 -134
  28. data/lib/rsmp/rsmp.rb +1 -1
  29. data/lib/rsmp/site.rb +24 -61
  30. data/lib/rsmp/site_proxy.rb +33 -37
  31. data/lib/rsmp/supervisor.rb +25 -21
  32. data/lib/rsmp/supervisor_proxy.rb +55 -29
  33. data/lib/rsmp/task.rb +84 -0
  34. data/lib/rsmp/tlc/signal_group.rb +17 -7
  35. data/lib/rsmp/tlc/signal_plan.rb +2 -2
  36. data/lib/rsmp/tlc/traffic_controller.rb +125 -39
  37. data/lib/rsmp/tlc/traffic_controller_site.rb +51 -35
  38. data/lib/rsmp/version.rb +1 -1
  39. data/lib/rsmp.rb +1 -1
  40. data/rsmp.gemspec +7 -7
  41. metadata +20 -20
  42. data/lib/rsmp/site_proxy_wait.rb +0 -0
  43. data/lib/rsmp/wait.rb +0 -16
  44. data/test.rb +0 -27
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f54121873905da2e5ffa4914f4f454fc4b59c7283e482b6b89b4035d686b7779
4
- data.tar.gz: 523d2e310ebec8f4df07592fcb501d91f604ba8ea1c4625482c7d8d011340a6f
3
+ metadata.gz: dde978c380def64dfcad00d0a7c9845a7c57476828623664dcf2ace7f3f6b669
4
+ data.tar.gz: 6dadc564b21089271b9921f876b95c899ad42c5bbc27b9250d34b47648447937
5
5
  SHA512:
6
- metadata.gz: 807d2283a18f4a9c4e45594d4ae85e75464cde3792eb941342a825e8765a00d21f7d541fac03191680e28eb7e4af4c6624cb6ce80486da191cf3bc2b3f2d6431
7
- data.tar.gz: 6adc50becc91e2deab2c8099808a492a2440d072188227147742bd51ec1310f8a1075e3bed72f2989581ba11125b9beeda8134704d8a42e131ac1dac9a76eca1
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.3
1
+ 3.1.0
data/Gemfile.lock CHANGED
@@ -1,27 +1,21 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rsmp (0.8.3)
4
+ rsmp (0.9.0)
5
5
  async (~> 1.29.1)
6
- async-io (~> 1.32.1)
6
+ async-io (~> 1.32.2)
7
7
  colorize (~> 0.8.1)
8
8
  rsmp_schemer
9
- thor (~> 1.0.1)
9
+ thor (~> 1.2.1)
10
10
 
11
11
  GEM
12
12
  remote: https://rubygems.org/
13
13
  specs:
14
- activesupport (6.1.4)
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 (>= 2.4, < 7.0)
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 (6.1.0)
33
+ cucumber (7.1.0)
41
34
  builder (~> 3.2, >= 3.2.4)
42
- cucumber-core (~> 9.0, >= 9.0.1)
43
- cucumber-create-meta (~> 4.0, >= 4.0.0)
44
- cucumber-cucumber-expressions (~> 12.1, >= 12.1.1)
45
- cucumber-gherkin (~> 18.1, >= 18.1.0)
46
- cucumber-html-formatter (~> 13.0, >= 13.0.0)
47
- cucumber-messages (~> 15.0, >= 15.0.0)
48
- cucumber-wire (~> 5.0, >= 5.0.1)
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 (9.0.1)
54
- cucumber-gherkin (~> 18.1, >= 18.1.0)
55
- cucumber-messages (~> 15.0, >= 15.0.0)
56
- cucumber-tag-expressions (~> 3.0, >= 3.0.1)
57
- cucumber-create-meta (4.0.0)
58
- cucumber-messages (~> 15.0, >= 15.0.0)
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 (12.1.1)
61
- cucumber-gherkin (18.1.1)
62
- cucumber-messages (~> 15.0, >= 15.0.0)
63
- cucumber-html-formatter (13.0.0)
64
- cucumber-messages (~> 15.0, >= 15.0.0)
65
- cucumber-messages (15.0.0)
66
- protobuf-cucumber (~> 3.10, >= 3.10.8)
67
- cucumber-tag-expressions (3.0.1)
68
- cucumber-wire (5.0.1)
69
- cucumber-core (~> 9.0, >= 9.0.1)
70
- cucumber-cucumber-expressions (~> 12.1, >= 12.1.1)
71
- cucumber-messages (~> 15.0, >= 15.0.0)
72
- diff-lcs (1.4.4)
73
- ecma-re-validator (0.3.0)
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
- middleware (0.1.0)
86
- mime-types (3.3.1)
74
+ mime-types (3.4.1)
87
75
  mime-types-data (~> 3.2015)
88
- mime-types-data (3.2021.0225)
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
- protobuf-cucumber (3.10.8)
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.1)
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.2)
95
+ rspec-support (3.10.3)
114
96
  sys-uname (1.2.2)
115
97
  ffi (~> 1.1)
116
- thor (1.0.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 (~> 1.1.2)
131
- bundler (~> 2.2.21)
132
- cucumber (~> 6.1.0)
133
- rake (~> 13.0.3)
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.1)
115
+ rspec-expectations (~> 3.10.2)
137
116
  timecop (~> 0.9.4)
138
117
 
139
118
  BUNDLED WITH
140
- 2.2.32
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
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env ruby
2
2
 
3
3
  # Make IRB run inside Async, so async task
4
- # will run the the background.
4
+ # will run the the background.
5
5
 
6
6
  require 'bundler/setup'
7
7
  require 'irb'
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
- Handle logging.
17
+ Handles logging.
18
18
 
19
- ### Wait
20
- Handles waiting for an async condition and block.
19
+ ### Task
20
+ Handles async tasks.
21
21
 
22
22
  ### Components
23
- Component handling.
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
- site_class.new(site_settings:settings, log_settings: log_settings).start
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
- RSMP::Supervisor.new(supervisor_settings:settings,log_settings:log_settings).start
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: ['AggregatedStatus','MessageNotAck'], title: 'aggregated status' }
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 active?
54
+ # Is collection complete?
55
55
  def ok?
56
56
  @status == :ok
57
57
  end
58
58
 
59
- # Has collection time out?
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
- if collect(&block) == :timeout
98
- raise RSMP::TimeoutError.new describe_progress
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 RSMP::TimeoutError.new(describe_progress) if timeout?
130
+ raise @error if timeout?
124
131
  @messages
125
132
  end
126
133
 
@@ -3,7 +3,7 @@ module RSMP
3
3
  class CommandResponseCollector < StateCollector
4
4
  def initialize proxy, want, options={}
5
5
  super proxy, want, options.merge(
6
- type: ['CommandResponse','MessageNotAck'],
6
+ type: 'CommandResponse',
7
7
  title:'command response'
8
8
  )
9
9
  end
@@ -25,7 +25,7 @@ module RSMP
25
25
  # matches this input:
26
26
  #
27
27
  # {"cCI"=>"M0104", "n"=>"month", "v"=>"9", "age"=>"recent"}
28
- #
28
+ #
29
29
  # And the result is stored as:
30
30
  # {
31
31
  # {"cCI"=>"M0104", "cO"=>"setDate", "n"=>"month", "v"=>/\d+/} =>
@@ -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', type:['MessageNotAck'])
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
@@ -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