specwrk 0.1.1 → 0.1.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f06b10c3a81644d436c6b7b636c97c83b2b5bbb4c43065fa4a27554a5870b873
4
- data.tar.gz: '002619c27e85bbd6abaab2cb86a6e622549f20e5548087c87908421eb4aa78e4'
3
+ metadata.gz: 178a039de3ac828c35e8089e0dfceae2d7a5a367f93798a36f6028df331e8d74
4
+ data.tar.gz: 11f286c4b388fd982b50f22d17491306182fef27a9252018f0365d4609243a7e
5
5
  SHA512:
6
- metadata.gz: 61735c8eebc5bd13bdaafefd0925ed597b102fdb785bb821437bfb415654907a6262f11b8c2710b9c3913a6752816b4381c9315c55b0959877abb89e16280b46
7
- data.tar.gz: 97773a5c2e828e6fbf4562aa6eaea2e5f9ac9cf6e733959cb634b18e984e7e1ee48384eb5aa170bd89cd4de41f17cb14f372b6057e6ecbfc3c64cf9bcb3491fc
6
+ metadata.gz: 94873737c1ae2ef0087aaadc208d38fb9d376db62f7387a737d7deefd3a738b8f1747b908a8314a3520142766bdb583000f9059d46de24f5ee3b0836c09df493
7
+ data.tar.gz: 6cb10a86d95063fdf2d8baeec911d50e162a67af104b8053699fd6a823c165203708b28a47be4167035c84a2832d6dbd3cecc127ccc18258e65f87c10bcefc98
data/exe/specwrk CHANGED
@@ -5,7 +5,7 @@ require "specwrk/cli"
5
5
 
6
6
  trap("INT") do
7
7
  if Specwrk.starting_pid == Process.pid && !Specwrk.force_quit
8
- warn "Waiting for in-progress work to finish. Interrupt again to force quit (warning: at_exit hooks will be skipped if you force quit)."
8
+ warn "Waiting for in-progress work to finish. Interrupt again to force quit (warning: at_exit hooks will be skipped if you force quit)."
9
9
 
10
10
  Specwrk.force_quit = true
11
11
  elsif Specwrk.starting_pid != Process.pid
data/lib/specwrk/cli.rb CHANGED
@@ -15,10 +15,10 @@ module Specwrk
15
15
  extend Hookable
16
16
 
17
17
  on_included do |base|
18
- base.option :uri, type: :string, default: ENV.fetch("SPECWRK_SRV_URI", "https://localhost:#{ENV.fetch("SPECWRK_SRV_PORT", "5138")}"), desc: "HTTP URI of the server to pull jobs from"
19
- base.option :key, type: :string, default: ENV.fetch("SPECWRK_SRV_KEY", ""), aliases: ["-k"], desc: "Authentication key for accessing the server"
20
- base.option :run, type: :string, default: ENV.fetch("SPECWRK_SRV_KEY", "main"), aliases: ["-r"], desc: "The run identifier for this job execution"
21
- base.option :timeout, type: :integer, default: ENV.fetch("SPECWRK_TIMEOUT", "5"), aliases: ["-t"], desc: "The amount of time to wait for the server to respond"
18
+ base.unique_option :uri, type: :string, default: ENV.fetch("SPECWRK_SRV_URI", "https://localhost:#{ENV.fetch("SPECWRK_SRV_PORT", "5138")}"), desc: "HTTP URI of the server to pull jobs from. Overrides SPECWRK_SRV_PORT. Default 5138."
19
+ base.unique_option :key, type: :string, default: ENV.fetch("SPECWRK_SRV_KEY", ""), aliases: ["-k"], desc: "Authentication key clients must use for access. Overrides SPECWRK_SRV_KEY. Default ''."
20
+ base.unique_option :run, type: :string, default: ENV.fetch("SPECWRK_RUN", "main"), aliases: ["-r"], desc: "The run identifier for this job execution. Overrides SPECWRK_RUN. Default main."
21
+ base.unique_option :timeout, type: :integer, default: ENV.fetch("SPECWRK_TIMEOUT", "5"), aliases: ["-t"], desc: "The amount of time to wait for the server to respond. Overrides SPECWRK_TIMEOUT. Default 5."
22
22
  end
23
23
 
24
24
  on_setup do |uri:, key:, run:, timeout:, **|
@@ -33,9 +33,9 @@ module Specwrk
33
33
  extend Hookable
34
34
 
35
35
  on_included do |base|
36
- base.option :id, type: :string, default: "specwrk-worker", desc: "The identifier for this worker"
37
- base.option :count, type: :integer, default: 1, aliases: ["-c"], desc: "The number of worker processes you want to start"
38
- base.option :output, type: :string, default: ENV.fetch("SPECWRK_OUT", ".specwrk/"), aliases: ["-o"], desc: "Directory where worker output is stored"
36
+ base.unique_option :id, type: :string, default: "specwrk-worker", desc: "The identifier for this worker. Default specwrk-worker(-COUNT_INDEX)."
37
+ base.unique_option :count, type: :integer, default: 1, aliases: ["-c"], desc: "The number of worker processes you want to start. Default 1."
38
+ base.unique_option :output, type: :string, default: ENV.fetch("SPECWRK_OUT", ".specwrk/"), aliases: ["-o"], desc: "Directory where worker output is stored. Overrides SPECWRK_OUT. Default '.specwrk/'."
39
39
  end
40
40
 
41
41
  on_setup do |id:, count:, output:, **|
@@ -66,14 +66,17 @@ module Specwrk
66
66
  extend Hookable
67
67
 
68
68
  on_included do |base|
69
- base.option :port, type: :integer, default: ENV.fetch("SPECWRK_SRV_PORT", "5138"), aliases: ["-p"], desc: "Server port"
70
- base.option :key, type: :string, aliases: ["-k"], default: ENV.fetch("SPECWRK_SRV_KEY", ""), desc: "Authentication key clients must use for access"
71
- base.option :output, type: :string, default: ENV.fetch("SPECWRK_OUT", ".specwrk/"), aliases: ["-o"], desc: "Directory where worker output is stored"
72
- base.option :single_run, type: :boolean, default: !ENV["SPECWRK_SRV_SINGLE_RUN"].nil?, desc: "Act on shutdown requests from clients"
73
- base.option :group_by, values: %w[file timings], default: ENV.fetch("SPECWERK_SRV_GROUP_BY", "timings"), desc: "How examples will be grouped for workers; fallback to file if no timings are found"
69
+ base.unique_option :port, type: :integer, default: ENV.fetch("SPECWRK_SRV_PORT", "5138"), aliases: ["-p"], desc: "Server port. Overrides SPECWRK_SRV_PORT. Default 5138."
70
+ base.unique_option :bind, type: :string, default: ENV.fetch("SPECWRK_SRV_BIND", "127.0.0.1"), aliases: ["-b"], desc: "Server bind address. Overrides SPECWRK_SRV_BIND. Default 127.0.0.1."
71
+ base.unique_option :key, type: :string, aliases: ["-k"], default: ENV.fetch("SPECWRK_SRV_KEY", ""), desc: "Authentication key clients must use for access. Overrides SPECWRK_SRV_KEY. Default ''."
72
+ base.unique_option :output, type: :string, default: ENV.fetch("SPECWRK_OUT", ".specwrk/"), aliases: ["-o"], desc: "Directory where worker output is stored. Overrides SPECWRK_OUT. Default '.specwrk/'."
73
+ base.unique_option :group_by, values: %w[file timings], default: ENV.fetch("SPECWERK_SRV_GROUP_BY", "timings"), desc: "How examples will be grouped for workers; fallback to file if no timings are found. Overrides SPECWERK_SRV_GROUP_BY. Default timings."
74
+ base.unique_option :single_run, type: :boolean, default: false, desc: "Act on shutdown requests from clients. Default: false."
75
+ base.unique_option :verbose, type: :boolean, default: false, desc: "Run in verbose mode. Default false."
74
76
  end
75
77
 
76
- on_setup do |output:, port:, key:, single_run:, group_by:, **|
78
+ on_setup do |output:, port:, key:, single_run:, group_by:, verbose:, **|
79
+ ENV["SPECWRK_SRV_LOG"] = Pathname.new(File.join(output, "server.log")).expand_path(Dir.pwd).to_s if output && !verbose
77
80
  ENV["SPECWRK_SRV_OUTPUT"] = Pathname.new(File.join(output, "report.json")).expand_path(Dir.pwd).to_s if output
78
81
  ENV["SPECWRK_SRV_PORT"] = port
79
82
  ENV["SPECWRK_SRV_KEY"] = key
@@ -136,7 +139,7 @@ module Specwrk
136
139
  class Serve < Dry::CLI::Command
137
140
  include Servable
138
141
 
139
- desc "Start a server"
142
+ desc "Start a queue server"
140
143
 
141
144
  def call(**args)
142
145
  self.class.setup(**args)
@@ -170,6 +173,7 @@ module Specwrk
170
173
  Specwrk::Web::App.run!
171
174
  end
172
175
 
176
+ return if Specwrk.force_quit
173
177
  seed_pid = Process.fork do
174
178
  require "specwrk/list_examples"
175
179
  require "specwrk/client"
@@ -186,12 +190,15 @@ module Specwrk
186
190
 
187
191
  wait_for_pids_exit([seed_pid])
188
192
 
193
+ return if Specwrk.force_quit
189
194
  status "Starting #{worker_count} workers..."
190
195
  start_workers
191
196
 
192
197
  status "#{worker_count} workers started ✓\n"
193
198
  wait_for_pids_exit(@worker_pids)
194
199
 
200
+ return if Specwrk.force_quit
201
+
195
202
  require "specwrk/cli_reporter"
196
203
  status = Specwrk::CLIReporter.new.report
197
204
 
@@ -35,6 +35,10 @@ module Hookable
35
35
  end
36
36
 
37
37
  module ClassMethods
38
+ def unique_option(name, opts = {})
39
+ option(name, opts) unless options.find { |existing_option| existing_option.name == name }
40
+ end
41
+
38
42
  def setup(**args)
39
43
  setup_hooks.each { |blk| blk.call(**args) }
40
44
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Specwrk
4
- VERSION = "0.1.1"
4
+ VERSION = "0.1.3"
5
5
  end
@@ -10,33 +10,50 @@ rescue LoadError
10
10
  require "rack/handler/webrick"
11
11
  end
12
12
 
13
+ require "specwrk/web/logger"
13
14
  require "specwrk/web/auth"
14
15
  require "specwrk/web/endpoints"
15
16
 
16
17
  module Specwrk
17
18
  class Web
18
19
  class App
19
- def self.run!
20
- Process.setproctitle "specwrk-server"
20
+ class << self
21
+ def run!
22
+ Process.setproctitle "specwrk-server"
21
23
 
22
- server_opts = {
23
- Port: ENV.fetch("SPECWRK_SRV_PORT", "5138").to_i,
24
- Logger: WEBrick::Log.new($stdout, WEBrick::Log::FATAL),
25
- AccessLog: [],
26
- KeepAliveTimeout: 300
27
- }
24
+ if ENV["SPECWRK_SRV_LOG"]
25
+ $stdout.reopen(ENV["SPECWRK_SRV_LOG"], "w")
26
+ end
27
+
28
+ server_opts = {
29
+ Port: ENV.fetch("SPECWRK_SRV_PORT", "5138").to_i,
30
+ Host: ENV.fetch("SPECWRK_SRV_BIND", "127.0.0.1"),
31
+ Logger: WEBrick::Log.new($stdout, WEBrick::Log::FATAL),
32
+ AccessLog: [],
33
+ KeepAliveTimeout: 300
34
+ }
28
35
 
29
- # rack v3 or v2
30
- handler_klass = defined?(Rackup::Handler) ? Rackup::Handler::WEBrick : Rack::Handler.get("webrick")
36
+ # rack v3 or v2
37
+ handler_klass = defined?(Rackup::Handler) ? Rackup::Handler::WEBrick : Rack::Handler.get("webrick")
31
38
 
32
- handler_klass.run(rackup, **server_opts) do |server|
33
- ["INT", "TERM"].each do |sig|
34
- trap(sig) do
35
- puts "\n→ Shutting down gracefully..." unless ENV["SPECWRK_FORKED"]
36
- server.shutdown
39
+ handler_klass.run(rackup, **server_opts) do |server|
40
+ ["INT", "TERM"].each do |sig|
41
+ trap(sig) do
42
+ puts "\n→ Shutting down gracefully..." unless ENV["SPECWRK_FORKED"]
43
+ server.shutdown
44
+ end
37
45
  end
38
46
  end
39
47
  end
48
+
49
+ def rackup
50
+ Rack::Builder.new do
51
+ use Rack::Runtime
52
+ use Specwrk::Web::Logger, $stdout
53
+ use Specwrk::Web::Auth # global auth check
54
+ run Specwrk::Web::App.new # your router
55
+ end
56
+ end
40
57
  end
41
58
 
42
59
  def call(env)
@@ -47,13 +64,6 @@ module Specwrk
47
64
  .response
48
65
  end
49
66
 
50
- private_class_method def self.rackup
51
- Rack::Builder.new do
52
- use Specwrk::Web::Auth # global auth check
53
- run Specwrk::Web::App.new # your router
54
- end
55
- end
56
-
57
67
  def route(method:, path:)
58
68
  case [method, path]
59
69
  when ["GET", "/heartbeat"]
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Specwrk
4
+ class Web
5
+ class Logger
6
+ def initialize(app, out = $stdout)
7
+ @app, @out = app, out
8
+ end
9
+
10
+ def call(env)
11
+ start_time = Time.now
12
+ start = Process.clock_gettime(Process::CLOCK_MONOTONIC)
13
+ status, headers, body = @app.call(env)
14
+ dur_ms = ((Process.clock_gettime(Process::CLOCK_MONOTONIC) - start) * 1000).round(4)
15
+
16
+ remote = env["REMOTE_ADDR"] || env["REMOTE_HOST"] || "-"
17
+ @out.puts "#{remote} [#{start_time.iso8601(6)}] #{env["REQUEST_METHOD"]} #{env["PATH_INFO"]} → #{status} (#{dur_ms}ms)"
18
+ [status, headers, body]
19
+ end
20
+ end
21
+ end
22
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: specwrk
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel Westendorf
@@ -147,6 +147,7 @@ files:
147
147
  - lib/specwrk/web/app.rb
148
148
  - lib/specwrk/web/auth.rb
149
149
  - lib/specwrk/web/endpoints.rb
150
+ - lib/specwrk/web/logger.rb
150
151
  - lib/specwrk/worker.rb
151
152
  - lib/specwrk/worker/completion_formatter.rb
152
153
  - lib/specwrk/worker/executor.rb