cuboid 0.0.2alpha → 0.0.5

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.
Files changed (185) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +1 -1
  3. data/README.md +1 -0
  4. data/cuboid.gemspec +2 -2
  5. data/lib/cuboid/option_groups/dispatcher.rb +16 -0
  6. data/lib/cuboid/option_groups/paths.rb +12 -3
  7. data/lib/cuboid/processes/dispatchers.rb +15 -1
  8. data/lib/cuboid/processes/instances.rb +13 -1
  9. data/lib/cuboid/processes/schedulers.rb +15 -2
  10. data/lib/cuboid/rpc/server/application_wrapper.rb +4 -3
  11. data/lib/cuboid/rpc/server/dispatcher.rb +36 -7
  12. data/lib/cuboid/rpc/server/scheduler.rb +2 -1
  13. data/lib/version +1 -1
  14. data/spec/cuboid/option_groups/paths_spec.rb +6 -3
  15. data/spec/cuboid/rpc/server/dispatcher_spec.rb +147 -32
  16. data/spec/support/logs/Dispatcher - 1520492-37227.log +6 -0
  17. data/spec/support/logs/Dispatcher - 1520680-13689.log +6 -0
  18. data/spec/support/logs/Dispatcher - 1520682-24167.log +6 -0
  19. data/spec/support/logs/Dispatcher - 1520688-42731.log +6 -0
  20. data/spec/support/logs/Dispatcher - 1520690-5750.log +10 -0
  21. data/spec/support/logs/Dispatcher - 1520692-55183.log +10 -0
  22. data/spec/support/logs/Dispatcher - 1520695-39752.log +10 -0
  23. data/spec/support/logs/Dispatcher - 1520697-44327.log +10 -0
  24. data/spec/support/logs/Dispatcher - 1520699-58785.log +10 -0
  25. data/spec/support/logs/Dispatcher - 1520701-60952.log +10 -0
  26. data/spec/support/logs/Dispatcher - 1520796-50420.log +6 -0
  27. data/spec/support/logs/Dispatcher - 1520894-56883.log +6 -0
  28. data/spec/support/logs/Dispatcher - 1520896-21419.log +6 -0
  29. data/spec/support/logs/Dispatcher - 1520898-62584.log +6 -0
  30. data/spec/support/logs/Dispatcher - 1520900-59721.log +6 -0
  31. data/spec/support/logs/Dispatcher - 1520910-51632.log +6 -0
  32. data/spec/support/logs/Dispatcher - 1520920-21801.log +6 -0
  33. data/spec/support/logs/Dispatcher - 1520930-49223.log +6 -0
  34. data/spec/support/logs/Dispatcher - 1520933-34241.log +6 -0
  35. data/spec/support/logs/Dispatcher - 1520935-64571.log +6 -0
  36. data/spec/support/logs/Dispatcher - 1520937-50734.log +6 -0
  37. data/spec/support/logs/Dispatcher - 1520939-60841.log +6 -0
  38. data/spec/support/logs/Dispatcher - 1520944-8124.log +6 -0
  39. data/spec/support/logs/Dispatcher - 1520946-25192.log +16 -0
  40. data/spec/support/logs/Dispatcher - 1520948-9752.log +14 -0
  41. data/spec/support/logs/Dispatcher - 1520952-45543.log +10 -0
  42. data/spec/support/logs/Dispatcher - 1520958-36653.log +16 -0
  43. data/spec/support/logs/Dispatcher - 1520960-17456.log +14 -0
  44. data/spec/support/logs/Dispatcher - 1520964-5774.log +10 -0
  45. data/spec/support/logs/Dispatcher - 1520976-40848.log +16 -0
  46. data/spec/support/logs/Dispatcher - 1520978-29867.log +14 -0
  47. data/spec/support/logs/Dispatcher - 1520982-17715.log +10 -0
  48. data/spec/support/logs/Dispatcher - 1520987-8925.log +16 -0
  49. data/spec/support/logs/Dispatcher - 1520989-25480.log +14 -0
  50. data/spec/support/logs/Dispatcher - 1520993-5124.log +10 -0
  51. data/spec/support/logs/Dispatcher - 1520999-12901.log +16 -0
  52. data/spec/support/logs/Dispatcher - 1521004-32265.log +14 -0
  53. data/spec/support/logs/Dispatcher - 1521008-33455.log +10 -0
  54. data/spec/support/logs/Dispatcher - 1521014-13779.log +6 -0
  55. data/spec/support/logs/Dispatcher - 1521017-14755.log +6 -0
  56. data/spec/support/logs/Dispatcher - 1521022-48687.log +6 -0
  57. data/spec/support/logs/Dispatcher - 1521024-59097.log +6 -0
  58. data/spec/support/logs/Dispatcher - 1521034-12604.log +6 -0
  59. data/spec/support/logs/Dispatcher - 1521038-64272.log +6 -0
  60. data/spec/support/logs/Dispatcher - 1521043-8680.log +6 -0
  61. data/spec/support/logs/Dispatcher - 1521047-22949.log +6 -0
  62. data/spec/support/logs/Dispatcher - 1521051-3355.log +6 -0
  63. data/spec/support/logs/Dispatcher - 1521074-12332.log +6 -0
  64. data/spec/support/logs/Dispatcher - 1521118-53130.log +16 -0
  65. data/spec/support/logs/Dispatcher - 1521128-47137.log +14 -0
  66. data/spec/support/logs/Dispatcher - 1521136-30328.log +10 -0
  67. data/spec/support/logs/Dispatcher - 1521161-21329.log +16 -0
  68. data/spec/support/logs/Dispatcher - 1521172-19183.log +14 -0
  69. data/spec/support/logs/Dispatcher - 1521179-34902.log +10 -0
  70. data/spec/support/logs/Dispatcher - 1521190-20155.log +16 -0
  71. data/spec/support/logs/Dispatcher - 1521204-43843.log +14 -0
  72. data/spec/support/logs/Dispatcher - 1521211-23972.log +10 -0
  73. data/spec/support/logs/Dispatcher - 1521237-20879.log +10 -0
  74. data/spec/support/logs/Dispatcher - 1521239-61999.log +10 -0
  75. data/spec/support/logs/Dispatcher - 1521242-20975.log +16 -0
  76. data/spec/support/logs/Dispatcher - 1521246-28409.log +14 -0
  77. data/spec/support/logs/Dispatcher - 1521250-58505.log +10 -0
  78. data/spec/support/logs/Dispatcher - 1521262-53292.log +6 -0
  79. data/spec/support/logs/Dispatcher - 1521266-42758.log +6 -0
  80. data/spec/support/logs/Dispatcher - 1521277-4215.log +6 -0
  81. data/spec/support/logs/Dispatcher - 1521292-16086.log +6 -0
  82. data/spec/support/logs/Dispatcher - 1521301-42112.log +6 -0
  83. data/spec/support/logs/Dispatcher - 1521312-61196.log +6 -0
  84. data/spec/support/logs/Dispatcher - 1521316-23353.log +6 -0
  85. data/spec/support/logs/Dispatcher - 1521321-46361.log +6 -0
  86. data/spec/support/logs/Dispatcher - 1521438-46016.log +6 -0
  87. data/spec/support/logs/Dispatcher - 1521454-49862.log +6 -0
  88. data/spec/support/logs/Dispatcher - 1521470-54737.log +6 -0
  89. data/spec/support/logs/Instance - 1521353-26273.error.log +105 -0
  90. data/spec/support/logs/Instance - 1521355-56591.error.log +105 -0
  91. data/spec/support/logs/Instance - 1521363-26218.error.log +105 -0
  92. data/spec/support/logs/Scheduler - 1520469-35703.log +3 -0
  93. data/spec/support/logs/Scheduler - 1520473-60524.log +6 -0
  94. data/spec/support/logs/Scheduler - 1520509-34951.log +3 -0
  95. data/spec/support/logs/Scheduler - 1520517-31455.log +6 -0
  96. data/spec/support/logs/Scheduler - 1520529-43808.log +4 -0
  97. data/spec/support/logs/Scheduler - 1520536-23387.log +1 -0
  98. data/spec/support/logs/Scheduler - 1520549-48260.log +3 -0
  99. data/spec/support/logs/Scheduler - 1520563-45636.log +6 -0
  100. data/spec/support/logs/Scheduler - 1520599-40643.log +3 -0
  101. data/spec/support/logs/Scheduler - 1520608-54106.log +6 -0
  102. data/spec/support/logs/Scheduler - 1520629-24722.log +3 -0
  103. data/spec/support/logs/Scheduler - 1520637-61755.log +6 -0
  104. data/spec/support/logs/Scheduler - 1520663-17447.log +4 -0
  105. data/spec/support/logs/Scheduler - 1520671-38282.log +6 -0
  106. data/spec/support/logs/Scheduler - 1520703-33082.log +1 -0
  107. data/spec/support/logs/Scheduler - 1520706-22309.log +1 -0
  108. data/spec/support/logs/Scheduler - 1520709-1816.log +1 -0
  109. data/spec/support/logs/Scheduler - 1520711-19998.log +1 -0
  110. data/spec/support/logs/Scheduler - 1520714-47570.log +1 -0
  111. data/spec/support/logs/Scheduler - 1520723-18521.log +1 -0
  112. data/spec/support/logs/Scheduler - 1520725-40913.log +3 -0
  113. data/spec/support/logs/Scheduler - 1520749-45742.log +6 -0
  114. data/spec/support/logs/Scheduler - 1520759-44350.log +4 -0
  115. data/spec/support/logs/Scheduler - 1520770-53219.log +1 -0
  116. data/spec/support/logs/Scheduler - 1520773-54792.log +1 -0
  117. data/spec/support/logs/Scheduler - 1520777-19636.log +1 -0
  118. data/spec/support/logs/Scheduler - 1520780-51801.log +1 -0
  119. data/spec/support/logs/Scheduler - 1520782-9652.log +3 -0
  120. data/spec/support/logs/Scheduler - 1520786-59472.log +1 -0
  121. data/spec/support/logs/Scheduler - 1520789-1603.log +1 -0
  122. data/spec/support/logs/Scheduler - 1520792-35476.log +1 -0
  123. data/spec/support/logs/Scheduler - 1521410-47324.log +16 -0
  124. data/spec/support/logs/Scheduler - 1521422-33737.log +6 -0
  125. data/spec/support/logs/Scheduler - 1521433-36637.log +6 -0
  126. data/spec/support/logs/Scheduler - 1521440-15066.log +6 -0
  127. data/spec/support/logs/Scheduler - 1521456-48637.log +3 -0
  128. data/spec/support/logs/Scheduler - 1521472-54425.log +5 -0
  129. data/spec/support/logs/Scheduler - 1521496-12923.log +1 -0
  130. data/spec/support/logs/Scheduler - 1521518-46819.log +1 -0
  131. data/spec/support/logs/Scheduler - 1521522-21417.log +1 -0
  132. data/spec/support/logs/Scheduler - 1521525-35088.log +1 -0
  133. data/spec/support/logs/Scheduler - 1521528-13676.log +1 -0
  134. data/spec/support/logs/Scheduler - 1521530-48176.log +1 -0
  135. data/spec/support/logs/Scheduler - 1521532-13207.log +1 -0
  136. data/spec/support/logs/Scheduler - 1521535-5799.log +3 -0
  137. data/spec/support/logs/Scheduler - 1521543-62784.log +3 -0
  138. data/spec/support/logs/Scheduler - 1521551-10263.log +3 -0
  139. data/spec/support/logs/Scheduler - 1521556-56026.log +3 -0
  140. data/spec/support/logs/Scheduler - 1521560-14551.log +4 -0
  141. data/spec/support/logs/Scheduler - 1521573-47584.log +1 -0
  142. data/spec/support/logs/Scheduler - 1521578-14443.log +4 -0
  143. data/spec/support/logs/Scheduler - 1521580-60337.log +1 -0
  144. data/spec/support/logs/Scheduler - 1521583-52039.log +1 -0
  145. data/spec/support/logs/Scheduler - 1521586-1500.log +16 -0
  146. data/spec/support/logs/Scheduler - 1521598-61298.log +4 -0
  147. data/spec/support/logs/Scheduler - 1521602-61490.log +1 -0
  148. data/spec/support/logs/Scheduler - 1521604-29209.log +1 -0
  149. data/spec/support/logs/Scheduler - 1521606-47734.log +1 -0
  150. data/spec/support/logs/Scheduler - 1521612-63269.log +1 -0
  151. data/spec/support/logs/Scheduler - 1521614-47018.log +3 -0
  152. data/spec/support/logs/Scheduler - 1521619-32411.log +1 -0
  153. data/spec/support/logs/Scheduler - 1521621-42861.log +1 -0
  154. data/spec/support/logs/Scheduler - 1521623-56258.log +1 -0
  155. data/spec/support/logs/Scheduler - 1521627-9487.log +1 -0
  156. data/spec/support/logs/Scheduler - 1521630-3345.log +1 -0
  157. data/spec/support/logs/Scheduler - 1521632-47325.log +1 -0
  158. data/spec/support/logs/Scheduler - 1521635-22156.log +2 -0
  159. data/spec/support/logs/error-1520329.log +797 -0
  160. data/spec/support/logs/output_spec_1520329.log +390 -0
  161. data/spec/support/reports/003bed585153336c2548d1c60a026a3e.crf +0 -0
  162. data/spec/support/reports/30e3c7a8c13e9b40a0a443a5e5a4ff94.crf +0 -0
  163. data/spec/support/reports/31655751a9f0eee91e588bc796985b1e.crf +0 -0
  164. data/spec/support/reports/40801b7993c0ed919b73242a9c078dde.crf +0 -0
  165. data/spec/support/reports/4719b89667e92bb80102f4b0bb4c0c75.crf +0 -0
  166. data/spec/support/reports/4e765a3d2870d2763ea72167bd3db9d6.crf +0 -0
  167. data/spec/support/reports/61968f732d8ae715c104175e43679915.crf +0 -0
  168. data/spec/support/reports/63446a8ec637d9991b8c6a1151ae59a9.crf +0 -0
  169. data/spec/support/reports/737144b18305c7a115ad7964b9bbe41c.crf +0 -0
  170. data/spec/support/reports/73fe5f7adf905045c3fe4669bdf60d02.crf +0 -0
  171. data/spec/support/reports/86cd396db9ef97472876f32e57c44ce7.crf +0 -0
  172. data/spec/support/reports/8a031ac2b2730dfd07a1d1ca870299f2.crf +0 -0
  173. data/spec/support/reports/8e16ac74484ee5d8cf7073fe22adf787.crf +0 -0
  174. data/spec/support/reports/8eff857213ab6ff712a0b0e8582855c9.crf +0 -0
  175. data/spec/support/reports/9e0e6ed8718973b3d4e63bbb7dd1d1c6.crf +0 -0
  176. data/spec/support/reports/a9c88f967d09cb9c4e8e1180cfb24828.crf +0 -0
  177. data/spec/support/reports/ba32970a64686e45ec8caa5032f65c2e.crf +0 -0
  178. data/spec/support/reports/cceb7596659fd619ab4438953cbda78b.crf +0 -0
  179. data/spec/support/reports/d2e0f4558b605ffd1215e9226815b951.crf +0 -0
  180. data/spec/support/snapshots/Cuboid 2022-01-24 14_38_16 +0200 8238609e31cedaf1bcb89205f9d42121.csf +0 -0
  181. data/spec/support/snapshots/Cuboid 2022-01-24 14_38_30 +0200 68690b002e79c7bc9e3aabfcbc7ac5a7.csf +0 -0
  182. data/spec/support/snapshots/Cuboid 2022-01-24 14_46_39 +0200 6fd3c9491d3e784e18f9c3c0d9deddec.csf +0 -0
  183. data/spec/support/snapshots/Cuboid 2022-01-24 14_46_44 +0200 c3a012fba59210bc7c169afb0565d5a8.csf +0 -0
  184. data/spec/support/snapshots/Cuboid 2022-01-24 14_46_46 +0200 e4c1ce35d8e62e6a16f84eccd36b2283.csf +0 -0
  185. metadata +350 -12
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a5ce38e8ee0287c72c58608a0929e131603b2ef3ec44f2cc76c8cd1092045a72
4
- data.tar.gz: ee86c74160b1d21af33b84b153eb5b0315c214f6ec8481bb633ae22b0de9e0e0
3
+ metadata.gz: b01651b87b7bf659764002cbb1aaa3b8293caf047f9675874b7393dd36c54ced
4
+ data.tar.gz: 0b831b738a29e23eecdb949e17079294eb75b57cc902395ec54021cd2d923bee
5
5
  SHA512:
6
- metadata.gz: 8e339483ba06b2b5ab0f6eea74706d8ab7d9627c60c1e5aa9d4280ade3949ba826cdde536fc0e129ee8d531204d75fe1c38aa7e1060d4a0b3b7475f89cadfd07
7
- data.tar.gz: aa1337a9b9689f596d664961d6ebd6c030f40a693f505b7ccc6651f884a72a132e5c617565096569fb9f4e85d4d217d89f1366b25fddd50b09db266dd8d20f80
6
+ metadata.gz: 4aaca66ce49f16888f68e39d84c4d2d9e3f81b7cc8551b31ee6f74505d0c379a6aa92443e698724da65babd8d32c3f9cc5695c272cca4d5d0c2e4d9637d50f6a
7
+ data.tar.gz: 258a9295ef9d4765ef9f8cc9ff60ec53e2ee2b11cb342069db7574853ce7db8c1bceb242c80012170a52bba8b9e8f1a489d7969b150e0be15135aa70a0ba15b6
data/Gemfile CHANGED
@@ -1,6 +1,6 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
- gem 'rake', '11.3.0'
3
+ gem 'rake', '13.0.3'
4
4
 
5
5
  group :docs do
6
6
  gem 'yard'
data/README.md CHANGED
@@ -14,6 +14,7 @@ It offers:
14
14
  * No need to setup a topology manually, _**Dispatchers**_ will reach
15
15
  convergence on their own, just point them to an existing _**Grid**_ member.
16
16
  * Scaling up and down can be easily achieved by _plugging_ or _unplugging_ nodes.
17
+ * Horizontal (`default`) and vertical workload distribution strategies available.
17
18
  * Fault tolerant -- one application per process (_**Instance**_).
18
19
  * Self-healing -- keeps an eye out for disappearing and also re-appearing members.
19
20
  * A clean and simple framework for application development.
data/cuboid.gemspec CHANGED
@@ -35,7 +35,7 @@ Gem::Specification.new do |s|
35
35
  s.add_dependency 'concurrent-ruby-ext', '1.1.8'
36
36
 
37
37
  # For compressing/decompressing system state archives.
38
- s.add_dependency 'rubyzip', '1.2.2'
38
+ s.add_dependency 'rubyzip', '2.3.0'
39
39
 
40
40
  s.add_dependency 'childprocess', '0.8.0'
41
41
 
@@ -47,7 +47,7 @@ Gem::Specification.new do |s|
47
47
  s.add_dependency 'oj_mimic_json', '1.0.1'
48
48
 
49
49
  # Web server
50
- s.add_dependency 'puma', '3.10.0'
50
+ s.add_dependency 'puma', '5.5.2'
51
51
 
52
52
  s.add_dependency 'rack', '2.2.3'
53
53
  s.add_dependency 'rack-test'
@@ -5,6 +5,8 @@ module Cuboid::OptionGroups
5
5
  # @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
6
6
  class Dispatcher < Cuboid::OptionGroup
7
7
 
8
+ STRATEGIES = Set.new([:horizontal, :vertical])
9
+
8
10
  # @return [String]
9
11
  # URL of a {RPC::Server::Dispatcher}.
10
12
  attr_accessor :url
@@ -29,10 +31,24 @@ class Dispatcher < Cuboid::OptionGroup
29
31
  # Dispatcher name.
30
32
  attr_accessor :name
31
33
 
34
+ attr_accessor :strategy
35
+
32
36
  set_defaults(
37
+ strategy: :horizontal,
33
38
  ping_interval: 5.0,
34
39
  instance_port_range: [1025, 65535]
35
40
  )
36
41
 
42
+ def strategy=( type )
43
+ return @strategy = defaults[:strategy] if !type
44
+
45
+ type = type.to_sym
46
+ if !STRATEGIES.include? type
47
+ fail ArgumentError, "Unknown strategy type: #{type}"
48
+ end
49
+
50
+ @strategy = type
51
+ end
52
+
37
53
  end
38
54
  end
@@ -74,16 +74,21 @@ class Paths < Cuboid::OptionGroup
74
74
 
75
75
  def initialize
76
76
  @root = self.root_path
77
+ FileUtils.mkdir_p home_path
77
78
 
78
- @snapshots = self.config['snapshots'] || @root + 'snapshots/'
79
- @reports = self.config['reports'] || @root + 'reports/'
79
+ @snapshots = self.config['snapshots'] || home_path + 'snapshots/'
80
+ FileUtils.mkdir_p @snapshots
81
+
82
+ @reports = self.config['reports'] || home_path + 'reports/'
83
+ FileUtils.mkdir_p @reports
80
84
 
81
85
  if ENV['CUBOID_LOGDIR'].to_s != ''
82
86
  @logs = "#{ENV['CUBOID_LOGDIR']}/"
83
87
  elsif self.config['logs']
84
88
  @logs = self.config['logs']
85
89
  else
86
- @logs = "#{@root}logs/"
90
+ @logs = "#{home_path}logs/"
91
+ FileUtils.mkdir_p @logs
87
92
  end
88
93
 
89
94
  @lib = @root + 'lib/cuboid/'
@@ -98,6 +103,10 @@ class Paths < Cuboid::OptionGroup
98
103
  tmpdir
99
104
  end
100
105
 
106
+ def home_path
107
+ @home_path ||= "#{ENV['HOME']}/.cuboid/"
108
+ end
109
+
101
110
  def root_path
102
111
  self.class.root_path
103
112
  end
@@ -54,16 +54,30 @@ class Dispatchers
54
54
  #
55
55
  # @return [RPC::Client::Dispatcher]
56
56
  def spawn( options = {} )
57
+ options = options.dup
57
58
  fork = options.delete(:fork)
58
59
 
60
+ options[:ssl] ||= {
61
+ server: {},
62
+ client: {}
63
+ }
64
+
59
65
  options = {
60
66
  dispatcher: {
67
+ name: options[:name],
61
68
  neighbour: options[:neighbour],
69
+ strategy: options[:strategy],
62
70
  },
63
71
  rpc: {
64
72
  server_port: options[:port] || Utilities.available_port,
65
73
  server_address: options[:address] || '127.0.0.1',
66
- server_external_address: options[:external_address]
74
+ server_external_address: options[:external_address],
75
+
76
+ ssl_ca: options[:ssl][:ca],
77
+ server_ssl_private_key: options[:ssl][:server][:private_key],
78
+ server_ssl_certificate: options[:ssl][:server][:certificate],
79
+ client_ssl_private_key: options[:ssl][:client][:private_key],
80
+ client_ssl_certificate: options[:ssl][:client][:certificate],
67
81
  },
68
82
  paths: {
69
83
  application: options[:application] || Options.paths.application
@@ -61,16 +61,28 @@ class Instances
61
61
  # @return [RPC::Client::Instance, Integer]
62
62
  # RPC client and PID.
63
63
  def spawn( options = {}, &block )
64
+ options = options.dup
64
65
  token = options.delete(:token) || Utilities.generate_token
65
66
  fork = options.delete(:fork)
66
67
 
67
68
  port_range = options.delete( :port_range )
68
69
 
70
+ options[:ssl] ||= {
71
+ server: {},
72
+ client: {}
73
+ }
74
+
69
75
  options = {
70
76
  rpc: {
71
77
  server_socket: options[:socket],
72
78
  server_port: options[:port] || Utilities.available_port( port_range ),
73
- server_address: options[:address] || '127.0.0.1'
79
+ server_address: options[:address] || '127.0.0.1',
80
+
81
+ ssl_ca: options[:ssl][:ca],
82
+ server_ssl_private_key: options[:ssl][:server][:private_key],
83
+ server_ssl_certificate: options[:ssl][:server][:certificate],
84
+ client_ssl_private_key: options[:ssl][:client][:private_key],
85
+ client_ssl_certificate: options[:ssl][:client][:certificate],
74
86
  },
75
87
  paths: {
76
88
  application: options[:application] || Options.paths.application
@@ -52,16 +52,29 @@ class Schedulers
52
52
  #
53
53
  # @return [RPC::Client::Queue]
54
54
  def spawn( options = {} )
55
+ options = options.dup
55
56
  fork = options.delete(:fork)
56
57
 
58
+ options[:ssl] ||= {
59
+ server: {},
60
+ client: {}
61
+ }
62
+
57
63
  options = {
58
64
  dispatcher: {
59
- url: options[:dispatcher],
65
+ url: options[:dispatcher],
66
+ strategy: options[:strategy]
60
67
  },
61
68
  rpc: {
62
69
  server_port: options[:port] || Utilities.available_port,
63
70
  server_address: options[:address] || '127.0.0.1',
64
- server_external_address: options[:external_address]
71
+ server_external_address: options[:external_address],
72
+
73
+ ssl_ca: options[:ssl][:ca],
74
+ server_ssl_private_key: options[:ssl][:server][:private_key],
75
+ server_ssl_certificate: options[:ssl][:server][:certificate],
76
+ client_ssl_private_key: options[:ssl][:client][:private_key],
77
+ client_ssl_certificate: options[:ssl][:client][:certificate],
65
78
  },
66
79
  paths: {
67
80
  application: options[:application] || Options.paths.application
@@ -15,9 +15,10 @@ class ApplicationWrapper
15
15
  attr_reader :application
16
16
 
17
17
  extend Forwardable
18
- def_delegators :@application, :suspended?, :suspend!, :status,
19
- :pause!, :running?, :status_messages, :paused?,
20
- :snapshot_path, :restore!, :resume!, :generate_report
18
+ def_delegators :@application, :suspended?, :suspending?, :suspend!, :status,
19
+ :pause!, :running?, :status_messages, :paused?, :pausing?,
20
+ :snapshot_path, :restore!, :resume!, :generate_report,
21
+ :abort!, :aborting?, :aborted?
21
22
 
22
23
  # {RPC::Server::Application} error namespace.
23
24
  #
@@ -31,6 +31,8 @@ class Dispatcher
31
31
 
32
32
  SERVICE_NAMESPACE = Service
33
33
 
34
+ PREFERENCE_STRATEGIES = Cuboid::OptionGroups::Dispatcher::STRATEGIES
35
+
34
36
  def initialize( options = Options.instance )
35
37
  @options = options
36
38
 
@@ -77,13 +79,24 @@ class Dispatcher
77
79
  @server.alive?
78
80
  end
79
81
 
82
+ # @param [Symbol] strategy
83
+ # `:horizontal` -- Pick the Dispatcher with the least amount of workload.
84
+ # `:vertical` -- Pick the Dispatcher with the most amount of workload.
85
+ #
80
86
  # @return [String, nil]
81
- # Depending on availability:
87
+ # Depending on strategy and availability:
82
88
  #
83
- # * URL of the least burdened Dispatcher. If not a grid member it will
84
- # return this Dispatcher's URL.
85
- # * `nil` if all nodes are at max utilization.
86
- def preferred( &block )
89
+ # * URL of the preferred Dispatcher. If not a grid member it will return
90
+ # this Dispatcher's URL.
91
+ # * `nil` if all nodes are at max utilization or on error.
92
+ # * `ArgumentError` -- On invalid `strategy`.
93
+ def preferred( strategy = Cuboid::Options.dispatcher.strategy, &block )
94
+ strategy = strategy.to_sym
95
+ if !PREFERENCE_STRATEGIES.include? strategy
96
+ block.call :error_unknown_strategy
97
+ raise ArgumentError, "Unknown strategy: #{strategy}"
98
+ end
99
+
87
100
  if !@node.grid_member?
88
101
  block.call( self.utilization == 1 ? nil : @url )
89
102
  return
@@ -94,6 +107,16 @@ class Dispatcher
94
107
  nil : [url, utilization]
95
108
  end
96
109
 
110
+ adjust_score_by_strategy = proc do |score|
111
+ case strategy
112
+ when :horizontal
113
+ score
114
+
115
+ when :vertical
116
+ -score
117
+ end
118
+ end
119
+
97
120
  each = proc do |neighbour, iter|
98
121
  connect_to_peer( neighbour ).utilization do |utilization|
99
122
  iter.return pick_utilization.call( neighbour, utilization )
@@ -110,7 +133,7 @@ class Dispatcher
110
133
  next
111
134
  end
112
135
 
113
- block.call nodes.sort_by { |_, score| score }[0][0]
136
+ block.call nodes.sort_by { |_, score| adjust_score_by_strategy.call score }[0][0]
114
137
  end
115
138
 
116
139
  Arachni::Reactor.global.create_iterator( @node.neighbours ).map( each, after )
@@ -133,17 +156,23 @@ class Dispatcher
133
156
  # * `nil`: Max utilization, wait for one of the instances to finish and retry.
134
157
  def dispatch( options = {}, &block )
135
158
  options = options.my_symbolize_keys
159
+ strategy = options.delete(:strategy)
136
160
  owner = options[:owner]
137
161
  helpers = options[:helpers] || {}
138
162
  load_balance = options[:load_balance].nil? ? true : options[:load_balance]
139
163
 
140
164
  if load_balance && @node.grid_member?
141
- preferred do |url|
165
+ preferred *[strategy].compact do |url|
142
166
  if !url
143
167
  block.call
144
168
  next
145
169
  end
146
170
 
171
+ if url == :error_unknown_strategy
172
+ block.call :error_unknown_strategy
173
+ next
174
+ end
175
+
147
176
  connect_to_peer( url ).dispatch( options.merge(
148
177
  helpers: helpers.merge( via: @url ),
149
178
  load_balance: false
@@ -423,7 +423,8 @@ class Scheduler
423
423
  def spawn_instance( &block )
424
424
  if dispatcher
425
425
  options = {
426
- owner: self.class.to_s,
426
+ owner: self.class.to_s,
427
+ strategy: Cuboid::Options.dispatcher.strategy,
427
428
  helpers: {
428
429
  owner: {
429
430
  url: @url
data/lib/version CHANGED
@@ -1 +1 @@
1
- 0.0.2alpha
1
+ 0.0.5
@@ -70,7 +70,7 @@ describe Cuboid::OptionGroups::Paths do
70
70
 
71
71
  describe '#logs' do
72
72
  it 'returns the default location' do
73
- expect(subject.logs).to eq("#{subject.root}logs/")
73
+ expect(subject.logs).to eq("#{subject.home_path}logs/")
74
74
  end
75
75
 
76
76
  context 'when the CUBOID_LOGDIR environment variable' do
@@ -91,13 +91,14 @@ describe Cuboid::OptionGroups::Paths do
91
91
  end
92
92
 
93
93
  expect(described_class.new.logs).to eq('logs-stuff/')
94
+ @created_resources << described_class.new.logs
94
95
  end
95
96
  end
96
97
  end
97
98
 
98
99
  describe '#snapshots' do
99
100
  it 'returns the default location' do
100
- expect(subject.snapshots).to eq("#{subject.root}snapshots/")
101
+ expect(subject.snapshots).to eq("#{subject.home_path}snapshots/")
101
102
  end
102
103
 
103
104
  context "when #{described_class}.config['snapshots']" do
@@ -109,13 +110,14 @@ describe Cuboid::OptionGroups::Paths do
109
110
  end
110
111
 
111
112
  expect(described_class.new.snapshots).to eq('snapshots-stuff/')
113
+ @created_resources << described_class.new.snapshots
112
114
  end
113
115
  end
114
116
  end
115
117
 
116
118
  describe '#reports' do
117
119
  it 'returns the default location' do
118
- expect(subject.reports).to eq("#{subject.root}reports/")
120
+ expect(subject.reports).to eq("#{subject.home_path}reports/")
119
121
  end
120
122
 
121
123
  context "when #{described_class}.config['reports']" do
@@ -127,6 +129,7 @@ describe Cuboid::OptionGroups::Paths do
127
129
  end
128
130
 
129
131
  expect(described_class.new.reports).to eq('reports-stuff/')
132
+ @created_resources << described_class.new.reports
130
133
  end
131
134
  end
132
135
  end
@@ -20,11 +20,44 @@ describe Cuboid::RPC::Server::Dispatcher do
20
20
 
21
21
  describe '#preferred' do
22
22
  context 'when the dispatcher is a grid member' do
23
- it 'returns the URL of least burdened Dispatcher' do
24
- dispatcher_spawn( neighbour: subject.url ).dispatch( load_balance: false )
25
- dispatcher_spawn( neighbour: subject.url ).dispatch( load_balance: false )
23
+ context 'and strategy is' do
24
+ context :horizontal do
25
+ it 'returns the URL of least burdened Dispatcher' do
26
+ dispatcher_spawn( neighbour: subject.url ).dispatch( load_balance: false )
27
+ dispatcher_spawn( neighbour: subject.url ).dispatch( load_balance: false )
26
28
 
27
- expect(subject.preferred).to eq(subject.url)
29
+ expect(subject.preferred( :horizontal )).to eq(subject.url)
30
+ end
31
+ end
32
+
33
+ context :vertical do
34
+ it 'returns the URL of most burdened Dispatcher' do
35
+ dispatcher_spawn( neighbour: subject.url ).dispatch( load_balance: false )
36
+ d = dispatcher_spawn( neighbour: subject.url )
37
+ d.dispatch( load_balance: false )
38
+ d.dispatch( load_balance: false )
39
+
40
+ expect(subject.preferred( :vertical )).to eq(d.url)
41
+ end
42
+ end
43
+
44
+ context 'default' do
45
+ it 'returns the URL of least burdened Dispatcher' do
46
+ dispatcher_spawn( neighbour: subject.url ).dispatch( load_balance: false )
47
+ dispatcher_spawn( neighbour: subject.url ).dispatch( load_balance: false )
48
+
49
+ expect(subject.preferred).to eq(subject.url)
50
+ end
51
+ end
52
+
53
+ context 'other' do
54
+ it 'returns :error_unknown_strategy' do
55
+ dispatcher_spawn( neighbour: subject.url ).dispatch( load_balance: false )
56
+ dispatcher_spawn( neighbour: subject.url ).dispatch( load_balance: false )
57
+
58
+ expect(subject.preferred( :blah )).to eq('error_unknown_strategy')
59
+ end
60
+ end
28
61
  end
29
62
 
30
63
  context 'and all Dispatchers are at max utilization' do
@@ -154,40 +187,122 @@ describe Cuboid::RPC::Server::Dispatcher do
154
187
  context 'when a Grid member' do
155
188
  let(:slots) { 4 }
156
189
 
157
- it 'returns Instance info from the least burdened Dispatcher' do
158
- d1 = dispatcher_spawn(
159
- address: '127.0.0.1',
160
- application: "#{fixtures_path}/mock_app.rb"
161
- )
190
+ context 'and strategy is' do
191
+ context :horizontal do
192
+ it 'provides Instances from the least burdened Dispatcher' do
193
+ d1 = dispatcher_spawn(
194
+ address: '127.0.0.1',
195
+ application: "#{fixtures_path}/mock_app.rb"
196
+ )
162
197
 
163
- 3.times do
164
- d1.dispatch( load_balance: false )
198
+ 3.times do
199
+ d1.dispatch( load_balance: false )
200
+ end
201
+
202
+ d2 = dispatcher_spawn(
203
+ address: '127.0.0.2',
204
+ neighbour: d1.url,
205
+ application: "#{fixtures_path}/mock_app.rb"
206
+ )
207
+
208
+ 2.times do
209
+ d2.dispatch( load_balance: false )
210
+ end
211
+
212
+ d3 = dispatcher_spawn(
213
+ address: '127.0.0.3',
214
+ neighbour: d1.url,
215
+ application: "#{fixtures_path}/mock_app.rb"
216
+ )
217
+ d3.dispatch( load_balance: false )
218
+ preferred = d3.url.split( ':' ).first
219
+
220
+ expect(d3.dispatch(strategy: :horizontal )['url'].split( ':' ).first).to eq(preferred)
221
+ expect(%W{127.0.0.3 127.0.0.2}).to include d1.dispatch['url'].split( ':' ).first
222
+ expect(d2.dispatch(strategy: :horizontal )['url'].split( ':' ).first).to eq(preferred)
223
+ expect(%W{127.0.0.1 127.0.0.3}).to include d3.dispatch(strategy: :horizontal )['url'].split( ':' ).first
224
+ expect(%W{127.0.0.2 127.0.0.3}).to include d3.dispatch(strategy: :horizontal )['url'].split( ':' ).first
225
+ expect(%W{127.0.0.2 127.0.0.3}).to include d1.dispatch(strategy: :horizontal )['url'].split( ':' ).first
226
+ end
165
227
  end
166
228
 
167
- d2 = dispatcher_spawn(
168
- address: '127.0.0.2',
169
- neighbour: d1.url,
170
- application: "#{fixtures_path}/mock_app.rb"
171
- )
229
+ context :vertical do
230
+ it 'provides Instances from the most burdened Dispatcher' do
231
+ d1 = dispatcher_spawn(
232
+ address: '127.0.0.1',
233
+ application: "#{fixtures_path}/mock_app.rb"
234
+ )
172
235
 
173
- 2.times do
174
- d2.dispatch( load_balance: false )
236
+ 3.times do
237
+ d1.dispatch( load_balance: false )
238
+ end
239
+
240
+ d2 = dispatcher_spawn(
241
+ address: '127.0.0.2',
242
+ neighbour: d1.url,
243
+ application: "#{fixtures_path}/mock_app.rb"
244
+ )
245
+
246
+ 2.times do
247
+ d2.dispatch( load_balance: false )
248
+ end
249
+
250
+ d3 = dispatcher_spawn(
251
+ address: '127.0.0.3',
252
+ neighbour: d1.url,
253
+ application: "#{fixtures_path}/mock_app.rb"
254
+ )
255
+ d3.dispatch( load_balance: false )
256
+
257
+ preferred = d1.url.split( ':' ).first
258
+ expect(d3.dispatch( strategy: :vertical )['url'].split( ':' ).first).to eq(preferred)
259
+ end
175
260
  end
176
261
 
177
- d3 = dispatcher_spawn(
178
- address: '127.0.0.3',
179
- neighbour: d1.url,
180
- application: "#{fixtures_path}/mock_app.rb"
181
- )
182
- d3.dispatch( load_balance: false )
183
- preferred = d3.url.split( ':' ).first
184
-
185
- expect(d3.dispatch['url'].split( ':' ).first).to eq(preferred)
186
- expect(%W{127.0.0.3 127.0.0.2}).to include d1.dispatch['url'].split( ':' ).first
187
- expect(d2.dispatch['url'].split( ':' ).first).to eq(preferred)
188
- expect(%W{127.0.0.1 127.0.0.3}).to include d3.dispatch['url'].split( ':' ).first
189
- expect(%W{127.0.0.2 127.0.0.3}).to include d3.dispatch['url'].split( ':' ).first
190
- expect(%W{127.0.0.2 127.0.0.3}).to include d1.dispatch['url'].split( ':' ).first
262
+ context 'default' do
263
+ it 'provides Instances from the least burdened Dispatcher' do
264
+ d1 = dispatcher_spawn(
265
+ address: '127.0.0.1',
266
+ application: "#{fixtures_path}/mock_app.rb"
267
+ )
268
+
269
+ 3.times do
270
+ d1.dispatch( load_balance: false )
271
+ end
272
+
273
+ d2 = dispatcher_spawn(
274
+ address: '127.0.0.2',
275
+ neighbour: d1.url,
276
+ application: "#{fixtures_path}/mock_app.rb"
277
+ )
278
+
279
+ 2.times do
280
+ d2.dispatch( load_balance: false )
281
+ end
282
+
283
+ d3 = dispatcher_spawn(
284
+ address: '127.0.0.3',
285
+ neighbour: d1.url,
286
+ application: "#{fixtures_path}/mock_app.rb"
287
+ )
288
+ d3.dispatch( load_balance: false )
289
+ preferred = d3.url.split( ':' ).first
290
+
291
+ expect(d3.dispatch['url'].split( ':' ).first).to eq(preferred)
292
+ expect(%W{127.0.0.3 127.0.0.2}).to include d1.dispatch['url'].split( ':' ).first
293
+ expect(d2.dispatch['url'].split( ':' ).first).to eq(preferred)
294
+ expect(%W{127.0.0.1 127.0.0.3}).to include d3.dispatch['url'].split( ':' ).first
295
+ expect(%W{127.0.0.2 127.0.0.3}).to include d3.dispatch['url'].split( ':' ).first
296
+ expect(%W{127.0.0.2 127.0.0.3}).to include d1.dispatch['url'].split( ':' ).first
297
+ end
298
+ end
299
+
300
+ context 'other' do
301
+ it 'returns :error_unknown_strategy' do
302
+ expect(dispatcher_spawn( neighbour: subject.url ).
303
+ dispatch( strategy: 'blah' )).to eq('error_unknown_strategy')
304
+ end
305
+ end
191
306
  end
192
307
 
193
308
  context 'when the load-balance option is set to false' do
@@ -0,0 +1,6 @@
1
+ [Mon Jan 24 14:40:16 2022] [status] Starting the RPC Server...
2
+ [Mon Jan 24 14:40:16 2022] [status] Initializing grid node...
3
+ [Mon Jan 24 14:40:16 2022] [status] Node ready.
4
+ [Mon Jan 24 14:40:16 2022] [info] Updated neighbours:
5
+ [Mon Jan 24 14:40:16 2022] [info] <empty>
6
+ [Mon Jan 24 14:40:16 2022] [status] Ready
@@ -0,0 +1,6 @@
1
+ [Mon Jan 24 14:42:22 2022] [status] Starting the RPC Server...
2
+ [Mon Jan 24 14:42:22 2022] [status] Initializing grid node...
3
+ [Mon Jan 24 14:42:22 2022] [status] Node ready.
4
+ [Mon Jan 24 14:42:22 2022] [info] Updated neighbours:
5
+ [Mon Jan 24 14:42:22 2022] [info] <empty>
6
+ [Mon Jan 24 14:42:22 2022] [status] Ready
@@ -0,0 +1,6 @@
1
+ [Mon Jan 24 14:42:23 2022] [status] Starting the RPC Server...
2
+ [Mon Jan 24 14:42:23 2022] [status] Initializing grid node...
3
+ [Mon Jan 24 14:42:23 2022] [status] Node ready.
4
+ [Mon Jan 24 14:42:23 2022] [info] Updated neighbours:
5
+ [Mon Jan 24 14:42:23 2022] [info] <empty>
6
+ [Mon Jan 24 14:42:23 2022] [status] Ready
@@ -0,0 +1,6 @@
1
+ [Mon Jan 24 14:42:26 2022] [status] Starting the RPC Server...
2
+ [Mon Jan 24 14:42:26 2022] [status] Initializing grid node...
3
+ [Mon Jan 24 14:42:26 2022] [status] Node ready.
4
+ [Mon Jan 24 14:42:26 2022] [info] Updated neighbours:
5
+ [Mon Jan 24 14:42:26 2022] [info] <empty>
6
+ [Mon Jan 24 14:42:26 2022] [status] Ready
@@ -0,0 +1,10 @@
1
+ [Mon Jan 24 14:42:27 2022] [status] Starting the RPC Server...
2
+ [Mon Jan 24 14:42:27 2022] [status] Initializing grid node...
3
+ [Mon Jan 24 14:42:27 2022] [status] Node ready.
4
+ [Mon Jan 24 14:42:27 2022] [info] Updated neighbours:
5
+ [Mon Jan 24 14:42:27 2022] [info] <empty>
6
+ [Mon Jan 24 14:42:27 2022] [status] Ready
7
+ [Mon Jan 24 14:42:27 2022] [status] Adding neighbour: 127.0.0.1:55183
8
+ [Mon Jan 24 14:42:27 2022] [info] Updated neighbours:
9
+ [Mon Jan 24 14:42:27 2022] [info] ---- 127.0.0.1:55183
10
+ [Mon Jan 24 14:42:27 2022] [status] Advertising: 127.0.0.1:55183
@@ -0,0 +1,10 @@
1
+ [Mon Jan 24 14:42:27 2022] [status] Starting the RPC Server...
2
+ [Mon Jan 24 14:42:27 2022] [status] Initializing grid node...
3
+ [Mon Jan 24 14:42:27 2022] [status] Node ready.
4
+ [Mon Jan 24 14:42:27 2022] [info] Updated neighbours:
5
+ [Mon Jan 24 14:42:27 2022] [info] <empty>
6
+ [Mon Jan 24 14:42:27 2022] [status] Ready
7
+ [Mon Jan 24 14:42:27 2022] [status] Adding neighbour: 127.0.0.1:5750
8
+ [Mon Jan 24 14:42:27 2022] [info] Updated neighbours:
9
+ [Mon Jan 24 14:42:27 2022] [info] ---- 127.0.0.1:5750
10
+ [Mon Jan 24 14:42:27 2022] [status] Advertising: 127.0.0.1:5750
@@ -0,0 +1,10 @@
1
+ [Mon Jan 24 14:42:29 2022] [status] Starting the RPC Server...
2
+ [Mon Jan 24 14:42:29 2022] [status] Initializing grid node...
3
+ [Mon Jan 24 14:42:29 2022] [status] Node ready.
4
+ [Mon Jan 24 14:42:29 2022] [info] Updated neighbours:
5
+ [Mon Jan 24 14:42:29 2022] [info] <empty>
6
+ [Mon Jan 24 14:42:29 2022] [status] Ready
7
+ [Mon Jan 24 14:42:29 2022] [status] Adding neighbour: 127.0.0.1:44327
8
+ [Mon Jan 24 14:42:29 2022] [info] Updated neighbours:
9
+ [Mon Jan 24 14:42:29 2022] [info] ---- 127.0.0.1:44327
10
+ [Mon Jan 24 14:42:29 2022] [status] Advertising: 127.0.0.1:44327