cuboid 0.0.2alpha → 0.0.5

Sign up to get free protection for your applications and to get access to all the features.
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