flatware 0.4.1 → 2.0.0.rc2

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 (38) hide show
  1. checksums.yaml +5 -5
  2. data/README.md +38 -47
  3. data/bin/flatware +2 -2
  4. data/lib/flatware.rb +32 -3
  5. data/lib/flatware/broadcaster.rb +20 -3
  6. data/lib/flatware/cli.rb +45 -21
  7. data/lib/flatware/configuration.rb +40 -0
  8. data/lib/flatware/job.rb +13 -1
  9. data/lib/flatware/pid.rb +41 -0
  10. data/lib/flatware/serialized_exception.rb +16 -4
  11. data/lib/flatware/sink.rb +97 -65
  12. data/lib/flatware/sink/client.rb +7 -5
  13. data/lib/flatware/version.rb +3 -1
  14. data/lib/flatware/worker.rb +50 -31
  15. metadata +20 -81
  16. data/lib/flatware-cucumber.rb +0 -1
  17. data/lib/flatware-rspec.rb +0 -1
  18. data/lib/flatware/cucumber.rb +0 -50
  19. data/lib/flatware/cucumber/cli.rb +0 -22
  20. data/lib/flatware/cucumber/formatter.rb +0 -66
  21. data/lib/flatware/cucumber/formatters/console.rb +0 -48
  22. data/lib/flatware/cucumber/formatters/console/summary.rb +0 -65
  23. data/lib/flatware/cucumber/result.rb +0 -27
  24. data/lib/flatware/cucumber/runtime.rb +0 -36
  25. data/lib/flatware/cucumber/scenario_result.rb +0 -38
  26. data/lib/flatware/cucumber/step_result.rb +0 -30
  27. data/lib/flatware/pids.rb +0 -25
  28. data/lib/flatware/poller.rb +0 -35
  29. data/lib/flatware/processor_info.rb +0 -24
  30. data/lib/flatware/rspec.rb +0 -28
  31. data/lib/flatware/rspec/checkpoint.rb +0 -29
  32. data/lib/flatware/rspec/cli.rb +0 -16
  33. data/lib/flatware/rspec/example_notification.rb +0 -21
  34. data/lib/flatware/rspec/examples_notification.rb +0 -24
  35. data/lib/flatware/rspec/formatter.rb +0 -50
  36. data/lib/flatware/rspec/formatters/console.rb +0 -33
  37. data/lib/flatware/rspec/summary.rb +0 -26
  38. data/lib/flatware/socket.rb +0 -176
data/lib/flatware/sink.rb CHANGED
@@ -1,104 +1,136 @@
1
- require 'flatware'
1
+ require 'drb/drb'
2
+
2
3
  module Flatware
3
4
  module Sink
4
- extend self
5
+ module_function
6
+
7
+ def start_server(**args)
8
+ Server.new(**args).start
9
+ end
5
10
 
6
- def start_server(*args)
7
- Server.new(*args).start
11
+ def client
12
+ @client
13
+ end
14
+
15
+ def client=(client)
16
+ @client = client
8
17
  end
9
18
 
10
19
  class Server
11
- attr_reader :sink, :dispatch, :poller, :workers, :checkpoints, :jobs, :formatter
20
+ attr_reader :checkpoints, :completed_jobs, :formatter, :jobs, :queue, :sink, :workers
12
21
 
13
- def initialize(jobs:, formatter:, dispatch:, sink:, worker_count: 0)
22
+ def initialize(jobs:, formatter:, sink:, worker_count: 0, **)
23
+ @checkpoints = []
24
+ @completed_jobs = []
14
25
  @formatter = formatter
15
- @jobs = group_jobs(jobs, worker_count)
16
- @sink = Flatware.socket(ZMQ::PULL, bind: sink)
17
- @dispatch = Flatware.socket(ZMQ::REP, bind: dispatch)
18
- @poller = Poller.new(@sink, @dispatch)
26
+ @jobs = group_jobs(jobs, worker_count).freeze
27
+ @queue = @jobs.dup
28
+ @sink = sink
19
29
  @workers = Set.new(worker_count.times.to_a)
20
- @checkpoints = []
21
30
  end
22
31
 
23
32
  def start
24
- trap 'INT' do
25
- puts "Interrupted!"
26
- formatter.summarize checkpoints
27
- summarize_remaining
28
- puts "\n\nCleaning up. Please wait...\n"
29
- Flatware.close!
30
- Process.waitall
31
- puts "thanks."
32
- exit 1
33
- end
33
+ trap_interrupt
34
34
  formatter.jobs jobs
35
- listen.tap do
36
- Flatware.close
37
- end
35
+ DRb.start_service(sink, self, verbose: Flatware.verbose?)
36
+ DRb.thread.join
37
+ !failures?
38
38
  end
39
39
 
40
- def listen
41
- que = jobs.dup
42
- poller.each do |socket|
43
- message, content = socket.recv
44
-
45
- case message
46
- when :ready
47
- workers << content
48
- job = que.shift
49
- if job and not done?
50
- dispatch.send job
51
- else
52
- workers.delete content
53
- dispatch.send 'seppuku'
54
- end
55
- when :checkpoint
56
- checkpoints << content
57
- when :finished
58
- completed_jobs << content
59
- formatter.finished content
60
- else
61
- formatter.send message, content
62
- end
63
- break if workers.empty? and done?
40
+ def ready(worker)
41
+ job = queue.shift
42
+ if job && !(remaining_work.empty? || interruped?)
43
+ workers << worker
44
+ job
45
+ else
46
+ workers.delete worker
47
+ check_finished!
48
+ Job.sentinel
64
49
  end
65
- formatter.summarize(checkpoints)
66
- !failures?
50
+ end
51
+
52
+ def checkpoint(checkpoint)
53
+ checkpoints << checkpoint
54
+ end
55
+
56
+ def finished(job)
57
+ completed_jobs << job
58
+ formatter.finished(job)
59
+ check_finished!
60
+ end
61
+
62
+ def method_missing(name, *args)
63
+ super unless formatter.respond_to?(name)
64
+ Flatware.log(name, *args)
65
+ formatter.send(name, *args)
66
+ end
67
+
68
+ def respond_to_missing?(name, include_all)
69
+ formatter.respond_to?(name, include_all)
67
70
  end
68
71
 
69
72
  private
70
73
 
71
- def failures?
72
- checkpoints.any?(&:failures?) || completed_jobs.any?(&:failed?)
74
+ def trap_interrupt
75
+ Thread.main[:signals] = Queue.new
76
+
77
+ Thread.new(&method(:handle_interrupt))
78
+
79
+ trap 'INT' do
80
+ Thread.main[:signals] << :int
81
+ end
73
82
  end
74
83
 
75
- def summarize_remaining
76
- return if remaining_work.empty?
77
- formatter.summarize_remaining remaining_work
84
+ def handle_interrupt
85
+ Thread.main[:signals].pop
86
+ puts 'Interrupted!'
87
+ summarize_remaining
88
+ puts "\n\nCleaning up. Please wait...\n"
89
+ Process.waitall
90
+ puts 'done.'
91
+ abort
78
92
  end
79
93
 
80
- def log(*args)
81
- Flatware.log *args
94
+ def interruped?
95
+ signals = Thread.main[:signals]
96
+ signals && !signals.empty?
82
97
  end
83
98
 
84
- def completed_jobs
85
- @completed_jobs ||= []
99
+ def check_finished!
100
+ return unless [workers, remaining_work].all?(&:empty?)
101
+
102
+ DRb.stop_service
103
+ summarize
86
104
  end
87
105
 
88
- def done?
89
- remaining_work.empty?
106
+ def failures?
107
+ checkpoints.any?(&:failures?) || completed_jobs.any?(&:failed?)
108
+ end
109
+
110
+ def summarize_remaining
111
+ summarize
112
+ return if remaining_work.empty?
113
+
114
+ formatter.summarize_remaining remaining_work
90
115
  end
91
116
 
92
117
  def remaining_work
93
118
  jobs - completed_jobs
94
119
  end
95
120
 
121
+ def summarize
122
+ formatter.summarize(checkpoints)
123
+ end
124
+
96
125
  def group_jobs(jobs, worker_count)
97
126
  return jobs unless worker_count > 1
98
- jobs.group_by.with_index do |_,i|
99
- i % worker_count
100
- end.values.map do |jobs|
101
- Job.new(jobs.map(&:id), jobs.first.args)
127
+
128
+ jobs
129
+ .group_by
130
+ .with_index { |_, i| i % worker_count }
131
+ .values
132
+ .map do |job_group|
133
+ Job.new(job_group.map(&:id).flatten, jobs.first.args)
102
134
  end
103
135
  end
104
136
  end
@@ -1,15 +1,17 @@
1
- require 'flatware/socket'
1
+ require 'drb/drb'
2
+
2
3
  module Flatware
3
4
  module Sink
4
- extend self
5
+ module_function
6
+
5
7
  attr_accessor :client
6
8
 
7
9
  class Client
8
10
  def initialize(sink_endpoint)
9
- @socket = Flatware.socket ZMQ::PUSH, connect: sink_endpoint
11
+ @sink = DRbObject.new_with_uri sink_endpoint
10
12
  end
11
13
 
12
- %w[finished started progress checkpoint].each do |message|
14
+ %w[ready finished started progress checkpoint].each do |message|
13
15
  define_method message do |content|
14
16
  push [message.to_sym, content]
15
17
  end
@@ -18,7 +20,7 @@ module Flatware
18
20
  private
19
21
 
20
22
  def push(message)
21
- @socket.send message
23
+ @sink.public_send message
22
24
  end
23
25
  end
24
26
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Flatware
2
- VERSION = '0.4.1'
4
+ VERSION = '2.0.0.rc2'
3
5
  end
@@ -1,57 +1,76 @@
1
- require 'flatware/sink/client'
1
+ # frozen_string_literal: true
2
+
3
+ require 'drb/drb'
4
+
2
5
  module Flatware
6
+ require 'flatware/configuration'
7
+ # executes tests and sends results to the sink
3
8
  class Worker
4
- attr_reader :id
9
+ attr_reader :sink, :runner, :id
5
10
 
6
- def initialize(id, runner, dispatch_endpoint, sink_endpoint)
11
+ def initialize(id, runner, sink_endpoint)
7
12
  @id = id
8
13
  @runner = runner
9
- @sink = Sink::Client.new sink_endpoint
10
- @task = Flatware.socket ZMQ::REQ, connect: dispatch_endpoint
14
+ @sink = DRbObject.new_with_uri sink_endpoint
15
+ Flatware::Sink.client = @sink
11
16
  end
12
17
 
13
- def self.spawn(count:, runner:, dispatch:, sink:)
18
+ def self.spawn(count:, runner:, sink:, **)
19
+ Flatware.configuration.before_fork.call
14
20
  count.times do |i|
15
21
  fork do
16
22
  $0 = "flatware worker #{i}"
17
23
  ENV['TEST_ENV_NUMBER'] = i.to_s
18
- new(i, runner, dispatch, sink).listen
24
+ Flatware.configuration.after_fork.call(i)
25
+ new(i, runner, sink).listen
19
26
  end
20
27
  end
21
28
  end
22
29
 
23
30
  def listen
24
- trap 'INT' do
25
- Flatware.close!
26
- @want_to_quit = true
27
- exit(1)
28
- end
29
-
30
- Sink.client = sink
31
- report_for_duty
32
- loop do
33
- job = task.recv
34
- break if job == 'seppuku' or @want_to_quit
35
- job.worker = id
36
- sink.started job
37
- begin
38
- runner.run job.id, job.args
39
- rescue => e
40
- Flatware.log e
41
- job.failed = true
31
+ retrying(times: 10, wait: 0.1) do
32
+ job = sink.ready id
33
+ until want_to_quit? || job.sentinel?
34
+ job.worker = id
35
+ sink.started job
36
+ run job
37
+ job = sink.ready id
42
38
  end
43
- sink.finished job
44
- report_for_duty
45
39
  end
46
- Flatware.close unless @want_to_quit
47
40
  end
48
41
 
49
42
  private
50
43
 
51
- attr_reader :task, :sink, :runner
44
+ def run(job)
45
+ runner.run job.id, job.args
46
+ sink.finished job
47
+ rescue Interrupt
48
+ want_to_quit!
49
+ rescue StandardError => e
50
+ Flatware.log e
51
+ job.failed!
52
+ sink.finished job
53
+ end
52
54
 
53
- def report_for_duty
54
- task.send [:ready, id]
55
+ def want_to_quit!
56
+ @want_to_quit = true
57
+ end
58
+
59
+ def want_to_quit?
60
+ @want_to_quit == true
61
+ end
62
+
63
+ def retrying(times:, wait:)
64
+ tries = 0
65
+ begin
66
+ yield unless want_to_quit?
67
+ rescue DRb::DRbConnError => e
68
+ raise if (tries += 1) >= times
69
+
70
+ sleep wait
71
+ Flatware.log('retrying', e.message)
72
+ retry
73
+ end
55
74
  end
56
75
  end
57
76
  end
metadata CHANGED
@@ -1,72 +1,30 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flatware
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 2.0.0.rc2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brian Dunn
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-03-16 00:00:00.000000000 Z
11
+ date: 2021-03-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: ffi-rzmq
14
+ name: thor
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - "~>"
17
+ - - "<"
18
18
  - !ruby/object:Gem::Version
19
19
  version: '2.0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - "~>"
24
+ - - "<"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '2.0'
27
- - !ruby/object:Gem::Dependency
28
- name: thor
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - "~>"
32
- - !ruby/object:Gem::Version
33
- version: '0.13'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - "~>"
39
- - !ruby/object:Gem::Version
40
- version: '0.13'
41
- - !ruby/object:Gem::Dependency
42
- name: aruba
43
- requirement: !ruby/object:Gem::Requirement
44
- requirements:
45
- - - "~>"
46
- - !ruby/object:Gem::Version
47
- version: '0.14'
48
- type: :development
49
- prerelease: false
50
- version_requirements: !ruby/object:Gem::Requirement
51
- requirements:
52
- - - "~>"
53
- - !ruby/object:Gem::Version
54
- version: '0.14'
55
- - !ruby/object:Gem::Dependency
56
- name: rake
57
- requirement: !ruby/object:Gem::Requirement
58
- requirements:
59
- - - "~>"
60
- - !ruby/object:Gem::Version
61
- version: 10.1.0
62
- type: :development
63
- prerelease: false
64
- version_requirements: !ruby/object:Gem::Requirement
65
- requirements:
66
- - - "~>"
67
- - !ruby/object:Gem::Version
68
- version: 10.1.0
69
- description: A distributed cucumber and rspec runner
27
+ description: A distributed rspec and cucumber runner
70
28
  email: brian@hashrocket.com
71
29
  executables:
72
30
  - flatware
@@ -78,60 +36,41 @@ files:
78
36
  - LICENSE.txt
79
37
  - README.md
80
38
  - bin/flatware
81
- - lib/flatware-cucumber.rb
82
- - lib/flatware-rspec.rb
83
39
  - lib/flatware.rb
84
40
  - lib/flatware/broadcaster.rb
85
41
  - lib/flatware/cli.rb
86
- - lib/flatware/cucumber.rb
87
- - lib/flatware/cucumber/cli.rb
88
- - lib/flatware/cucumber/formatter.rb
89
- - lib/flatware/cucumber/formatters/console.rb
90
- - lib/flatware/cucumber/formatters/console/summary.rb
91
- - lib/flatware/cucumber/result.rb
92
- - lib/flatware/cucumber/runtime.rb
93
- - lib/flatware/cucumber/scenario_result.rb
94
- - lib/flatware/cucumber/step_result.rb
42
+ - lib/flatware/configuration.rb
95
43
  - lib/flatware/job.rb
96
- - lib/flatware/pids.rb
97
- - lib/flatware/poller.rb
98
- - lib/flatware/processor_info.rb
99
- - lib/flatware/rspec.rb
100
- - lib/flatware/rspec/checkpoint.rb
101
- - lib/flatware/rspec/cli.rb
102
- - lib/flatware/rspec/example_notification.rb
103
- - lib/flatware/rspec/examples_notification.rb
104
- - lib/flatware/rspec/formatter.rb
105
- - lib/flatware/rspec/formatters/console.rb
106
- - lib/flatware/rspec/summary.rb
44
+ - lib/flatware/pid.rb
107
45
  - lib/flatware/serialized_exception.rb
108
46
  - lib/flatware/sink.rb
109
47
  - lib/flatware/sink/client.rb
110
- - lib/flatware/socket.rb
111
48
  - lib/flatware/version.rb
112
49
  - lib/flatware/worker.rb
113
50
  homepage: http://github.com/briandunn/flatware
114
51
  licenses:
115
52
  - MIT
116
53
  metadata: {}
117
- post_install_message:
54
+ post_install_message:
118
55
  rdoc_options: []
119
56
  require_paths:
120
57
  - lib
121
58
  required_ruby_version: !ruby/object:Gem::Requirement
122
59
  requirements:
123
- - - "~>"
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ version: '2.6'
63
+ - - "<"
124
64
  - !ruby/object:Gem::Version
125
- version: '2.1'
65
+ version: '3.1'
126
66
  required_rubygems_version: !ruby/object:Gem::Requirement
127
67
  requirements:
128
- - - ">="
68
+ - - ">"
129
69
  - !ruby/object:Gem::Version
130
- version: '0'
70
+ version: 1.3.1
131
71
  requirements: []
132
- rubyforge_project:
133
- rubygems_version: 2.6.14
134
- signing_key:
72
+ rubygems_version: 3.2.3
73
+ signing_key:
135
74
  specification_version: 4
136
- summary: A distributed cucumber and rspec runner
75
+ summary: A distributed rspec and cucumber runner
137
76
  test_files: []