From cf57ef7ffa65adff0d125eda564cd4ab10131cf6 Mon Sep 17 00:00:00 2001 From: Soutaro Matsumoto Date: Sun, 23 Oct 2022 11:45:10 +0900 Subject: [PATCH 1/6] Fix Steepfile Let `rbs collection` manage RBS files of `rbs` gem. --- Steepfile | 1 - rbs_collection.steep.lock.yaml | 24 ++++++++++++++++++++---- rbs_collection.steep.yaml | 1 - 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/Steepfile b/Steepfile index 036e3dea6..9d36c86bd 100644 --- a/Steepfile +++ b/Steepfile @@ -10,7 +10,6 @@ target :app do hash[D::Ruby::MethodDefinitionMissing] = :hint end - signature "../rbs/sig", "../rbs/stdlib/rdoc/0" library( "set", "pathname", diff --git a/rbs_collection.steep.lock.yaml b/rbs_collection.steep.lock.yaml index 5dd3c49ab..a979ccc2b 100644 --- a/rbs_collection.steep.lock.yaml +++ b/rbs_collection.steep.lock.yaml @@ -10,6 +10,10 @@ gems: version: '0' source: type: stdlib +- name: rbs + version: 2.7.0 + source: + type: rubygems - name: dbm version: '0' source: @@ -98,6 +102,22 @@ gems: version: '0' source: type: stdlib +- name: pathname + version: '0' + source: + type: stdlib +- name: optparse + version: '0' + source: + type: stdlib +- name: tsort + version: '0' + source: + type: stdlib +- name: rdoc + version: '0' + source: + type: stdlib - name: monitor version: '0' source: @@ -118,10 +138,6 @@ gems: version: '0' source: type: stdlib -- name: pathname - version: '0' - source: - type: stdlib - name: forwardable version: '0' source: diff --git a/rbs_collection.steep.yaml b/rbs_collection.steep.yaml index 8f48146ab..99bdaa424 100644 --- a/rbs_collection.steep.yaml +++ b/rbs_collection.steep.yaml @@ -15,7 +15,6 @@ gems: ignore: true - name: set - name: rbs - ignore: true - name: with_steep_types ignore: true - name: dbm From 6b4e98cc8f21ad1935da81cbd07d02ec4a10cc22 Mon Sep 17 00:00:00 2001 From: Soutaro Matsumoto Date: Sun, 23 Oct 2022 11:54:14 +0900 Subject: [PATCH 2/6] Type check WorkerProcess --- lib/steep/server/worker_process.rb | 4 +-- sig/steep/server/worker_process.rbs | 51 ++++++++++++++++++++++------- 2 files changed, 41 insertions(+), 14 deletions(-) diff --git a/lib/steep/server/worker_process.rb b/lib/steep/server/worker_process.rb index 9bb4069ef..a9996171d 100644 --- a/lib/steep/server/worker_process.rb +++ b/lib/steep/server/worker_process.rb @@ -38,9 +38,9 @@ def self.spawn_worker(type, name:, steepfile:, steep_command: "steep", options: end stdin, stdout, thread = if Gem.win_platform? - Open3.popen2(*command, new_pgroup: true) + __skip__ = Open3.popen2(*command, new_pgroup: true) else - Open3.popen2(*command, pgroup: true) + __skip__ = Open3.popen2(*command, pgroup: true) end stderr = nil diff --git a/sig/steep/server/worker_process.rbs b/sig/steep/server/worker_process.rbs index 632136eea..e8d8c49ba 100644 --- a/sig/steep/server/worker_process.rbs +++ b/sig/steep/server/worker_process.rbs @@ -1,29 +1,56 @@ module Steep module Server class WorkerProcess - attr_reader reader: untyped + interface _ProcessWaitThread + def pid: () -> Integer + end - attr_reader writer: untyped + attr_reader reader: LanguageServer::Protocol::Transport::Io::Reader - attr_reader stderr: untyped + attr_reader writer: LanguageServer::Protocol::Transport::Io::Writer - attr_reader name: untyped + attr_reader stderr: IO? - attr_reader wait_thread: untyped + attr_reader name: String - attr_reader index: untyped + attr_reader wait_thread: Thread & _ProcessWaitThread - def initialize: (reader: untyped, writer: untyped, stderr: untyped, wait_thread: untyped, name: untyped, ?index: untyped?) -> void + attr_reader index: Integer? - def self.spawn_worker: (untyped `type`, name: untyped, steepfile: untyped, ?steep_command: ::String, ?options: untyped, ?delay_shutdown: bool, ?index: untyped?) -> untyped + def initialize: ( + reader: LanguageServer::Protocol::Transport::Io::Reader, + writer: LanguageServer::Protocol::Transport::Io::Writer, + stderr: IO?, + wait_thread: Thread & _ProcessWaitThread, + name: String, + ?index: Integer? + ) -> void - def self.spawn_typecheck_workers: (steepfile: untyped, args: untyped, ?steep_command: ::String, ?count: untyped, ?delay_shutdown: bool) -> untyped + type worker_type = :interaction | :typecheck - def <<: (untyped message) -> untyped + def self.spawn_worker: ( + worker_type `type`, + name: String, + steepfile: Pathname, + ?steep_command: ::String, + ?options: Array[String], + ?delay_shutdown: bool, + ?index: Integer? + ) -> WorkerProcess - def read: () ?{ () -> untyped } -> untyped + def self.spawn_typecheck_workers: ( + steepfile: Pathname, + args: Array[String], + ?steep_command: ::String, + ?count: Integer, + ?delay_shutdown: bool + ) -> Array[WorkerProcess] - def kill: () -> untyped + def <<: (untyped message) -> void + + def read: () { (untyped) -> void } -> void + + def kill: () -> void end end end From d81a060d789761640905077fea8b8ff14fd78075 Mon Sep 17 00:00:00 2001 From: Soutaro Matsumoto Date: Sun, 23 Oct 2022 11:57:01 +0900 Subject: [PATCH 3/6] Type check Drivers/Worker --- sig/steep/drivers/worker.rbs | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/sig/steep/drivers/worker.rbs b/sig/steep/drivers/worker.rbs index ced90eb7a..d4d8bfcb9 100644 --- a/sig/steep/drivers/worker.rbs +++ b/sig/steep/drivers/worker.rbs @@ -1,31 +1,31 @@ module Steep module Drivers class Worker - attr_reader stdout: untyped + attr_reader stdout: IO - attr_reader stderr: untyped + attr_reader stderr: IO - attr_reader stdin: untyped + attr_reader stdin: IO - attr_accessor steepfile_path: untyped + attr_accessor steepfile_path: Pathname - attr_accessor worker_type: untyped + attr_accessor worker_type: Symbol - attr_accessor worker_name: untyped + attr_accessor worker_name: String - attr_accessor delay_shutdown: untyped + attr_accessor delay_shutdown: bool - attr_accessor max_index: untyped + attr_accessor max_index: Integer - attr_accessor index: untyped + attr_accessor index: Integer - attr_accessor commandline_args: untyped + attr_accessor commandline_args: Array[String] include Utils::DriverHelper - def initialize: (stdout: untyped, stderr: untyped, stdin: untyped) -> void + def initialize: (stdout: IO, stderr: IO, stdin: IO) -> void - def run: () -> 0 + def run: () -> Integer end end end From 5f5d60d72f1a1bb975480fc24aa4bde39c9b49c0 Mon Sep 17 00:00:00 2001 From: Soutaro Matsumoto Date: Mon, 24 Oct 2022 13:49:33 +0900 Subject: [PATCH 4/6] Remove unused `WorkerProcess#steepfile_path` --- lib/steep/drivers/worker.rb | 1 - sig/steep/drivers/worker.rbs | 2 -- 2 files changed, 3 deletions(-) diff --git a/lib/steep/drivers/worker.rb b/lib/steep/drivers/worker.rb index 0fc6bde49..4c6a59157 100644 --- a/lib/steep/drivers/worker.rb +++ b/lib/steep/drivers/worker.rb @@ -3,7 +3,6 @@ module Drivers class Worker attr_reader :stdout, :stderr, :stdin - attr_accessor :steepfile_path attr_accessor :worker_type attr_accessor :worker_name attr_accessor :delay_shutdown diff --git a/sig/steep/drivers/worker.rbs b/sig/steep/drivers/worker.rbs index d4d8bfcb9..cb548bc53 100644 --- a/sig/steep/drivers/worker.rbs +++ b/sig/steep/drivers/worker.rbs @@ -7,8 +7,6 @@ module Steep attr_reader stdin: IO - attr_accessor steepfile_path: Pathname - attr_accessor worker_type: Symbol attr_accessor worker_name: String From 30a4baf56dc474f0a07ef978d0434c7cc091b0a4 Mon Sep 17 00:00:00 2001 From: Soutaro Matsumoto Date: Sun, 23 Oct 2022 12:07:58 +0900 Subject: [PATCH 5/6] Rename spawn_*** to start_*** to make them more abstract --- lib/steep/drivers/check.rb | 2 +- lib/steep/drivers/checkfile.rb | 2 +- lib/steep/drivers/langserver.rb | 4 ++-- lib/steep/drivers/stats.rb | 2 +- lib/steep/drivers/watch.rb | 2 +- lib/steep/server/worker_process.rb | 6 +++--- sig/steep/server/worker_process.rbs | 20 ++++++++++++++++++-- test/master_test.rb | 16 ++++++++-------- 8 files changed, 35 insertions(+), 19 deletions(-) diff --git a/lib/steep/drivers/check.rb b/lib/steep/drivers/check.rb index d84535698..8df4bee80 100644 --- a/lib/steep/drivers/check.rb +++ b/lib/steep/drivers/check.rb @@ -36,7 +36,7 @@ def run server_reader = LanguageServer::Protocol::Transport::Io::Reader.new(server_read) server_writer = LanguageServer::Protocol::Transport::Io::Writer.new(server_write) - typecheck_workers = Server::WorkerProcess.spawn_typecheck_workers( + typecheck_workers = Server::WorkerProcess.start_typecheck_workers( steepfile: project.steepfile_path, args: command_line_patterns, delay_shutdown: true, diff --git a/lib/steep/drivers/checkfile.rb b/lib/steep/drivers/checkfile.rb index 199b5fa18..ad6046ac1 100644 --- a/lib/steep/drivers/checkfile.rb +++ b/lib/steep/drivers/checkfile.rb @@ -101,7 +101,7 @@ def run Steep.logger.info { "Starting #{count} workers for #{files.size} files..." } - typecheck_workers = Server::WorkerProcess.spawn_typecheck_workers( + typecheck_workers = Server::WorkerProcess.start_typecheck_workers( steepfile: project.steepfile_path, args: [], delay_shutdown: true, diff --git a/lib/steep/drivers/langserver.rb b/lib/steep/drivers/langserver.rb index ce8566d1f..9ec8321f7 100644 --- a/lib/steep/drivers/langserver.rb +++ b/lib/steep/drivers/langserver.rb @@ -35,8 +35,8 @@ def project def run @project = load_config() - interaction_worker = Server::WorkerProcess.spawn_worker(:interaction, name: "interaction", steepfile: project.steepfile_path, steep_command: jobs_option.steep_command_value) - typecheck_workers = Server::WorkerProcess.spawn_typecheck_workers(steepfile: project.steepfile_path, args: [], steep_command: jobs_option.steep_command_value, count: jobs_option.jobs_count_value) + interaction_worker = Server::WorkerProcess.start_worker(:interaction, name: "interaction", steepfile: project.steepfile_path, steep_command: jobs_option.steep_command_value) + typecheck_workers = Server::WorkerProcess.start_typecheck_workers(steepfile: project.steepfile_path, args: [], steep_command: jobs_option.steep_command_value, count: jobs_option.jobs_count_value) master = Server::Master.new( project: project, diff --git a/lib/steep/drivers/stats.rb b/lib/steep/drivers/stats.rb index da061f8ec..bd9cdd291 100644 --- a/lib/steep/drivers/stats.rb +++ b/lib/steep/drivers/stats.rb @@ -126,7 +126,7 @@ def run server_reader = LanguageServer::Protocol::Transport::Io::Reader.new(server_read) server_writer = LanguageServer::Protocol::Transport::Io::Writer.new(server_write) - typecheck_workers = Server::WorkerProcess.spawn_typecheck_workers( + typecheck_workers = Server::WorkerProcess.start_typecheck_workers( steepfile: project.steepfile_path, delay_shutdown: true, args: command_line_patterns, diff --git a/lib/steep/drivers/watch.rb b/lib/steep/drivers/watch.rb index 8210cf609..889b35589 100644 --- a/lib/steep/drivers/watch.rb +++ b/lib/steep/drivers/watch.rb @@ -42,7 +42,7 @@ def run() server_reader = LanguageServer::Protocol::Transport::Io::Reader.new(server_read) server_writer = LanguageServer::Protocol::Transport::Io::Writer.new(server_write) - typecheck_workers = Server::WorkerProcess.spawn_typecheck_workers(steepfile: project.steepfile_path, args: dirs.map(&:to_s), steep_command: jobs_option.steep_command_value, count: jobs_option.jobs_count_value) + typecheck_workers = Server::WorkerProcess.start_typecheck_workers(steepfile: project.steepfile_path, args: dirs.map(&:to_s), steep_command: jobs_option.steep_command_value, count: jobs_option.jobs_count_value) master = Server::Master.new( project: project, diff --git a/lib/steep/server/worker_process.rb b/lib/steep/server/worker_process.rb index a9996171d..2e797ac68 100644 --- a/lib/steep/server/worker_process.rb +++ b/lib/steep/server/worker_process.rb @@ -18,7 +18,7 @@ def initialize(reader:, writer:, stderr:, wait_thread:, name:, index: nil) @index = index end - def self.spawn_worker(type, name:, steepfile:, steep_command: "steep", options: [], delay_shutdown: false, index: nil) + def self.start_worker(type, name:, steepfile:, steep_command: "steep", options: [], delay_shutdown: false, index: nil) args = ["--name=#{name}", "--steepfile=#{steepfile}"] args << (%w(debug info warn error fatal unknown)[Steep.logger.level].yield_self {|log_level| "--log-level=#{log_level}" }) if Steep.log_output.is_a?(String) @@ -50,9 +50,9 @@ def self.spawn_worker(type, name:, steepfile:, steep_command: "steep", options: new(reader: reader, writer: writer, stderr: stderr, wait_thread: thread, name: name, index: index) end - def self.spawn_typecheck_workers(steepfile:, args:, steep_command: "steep", count: [Etc.nprocessors - 1, 1].max, delay_shutdown: false) + def self.start_typecheck_workers(steepfile:, args:, steep_command: "steep", count: [Etc.nprocessors - 1, 1].max, delay_shutdown: false) count.times.map do |i| - spawn_worker( + start_worker( :typecheck, name: "typecheck@#{i}", steepfile: steepfile, diff --git a/sig/steep/server/worker_process.rbs b/sig/steep/server/worker_process.rbs index e8d8c49ba..9a78ced9c 100644 --- a/sig/steep/server/worker_process.rbs +++ b/sig/steep/server/worker_process.rbs @@ -1,5 +1,21 @@ module Steep module Server + # WorkerProcess class represents a worker process + # + # Available operations are: + # + # 1. Sending a LSP message to the process + # 2. Receiving a LSP message from the process + # 3. Killing the process + # + # The process may be invoked by + # + # 1. `#fork` if available, or + # 2. `#spawn` otherwise + # + # `#fork` version is faster because it skips loading libraries. + # + # class WorkerProcess interface _ProcessWaitThread def pid: () -> Integer @@ -28,7 +44,7 @@ module Steep type worker_type = :interaction | :typecheck - def self.spawn_worker: ( + def self.start_worker: ( worker_type `type`, name: String, steepfile: Pathname, @@ -38,7 +54,7 @@ module Steep ?index: Integer? ) -> WorkerProcess - def self.spawn_typecheck_workers: ( + def self.start_typecheck_workers: ( steepfile: Pathname, args: Array[String], ?steep_command: ::String, diff --git a/test/master_test.rb b/test/master_test.rb index 4f94d8949..6fe3b61f5 100644 --- a/test/master_test.rb +++ b/test/master_test.rb @@ -526,8 +526,8 @@ def test_code_type_check project = Project.new(steepfile_path: steepfile) Project::DSL.parse(project, steepfile.read) - interaction_worker = Server::WorkerProcess.spawn_worker(:interaction, name: "interaction", steepfile: steepfile) - typecheck_workers = Server::WorkerProcess.spawn_typecheck_workers(steepfile: steepfile, count: 1, args: []) + interaction_worker = Server::WorkerProcess.start_worker(:interaction, name: "interaction", steepfile: steepfile) + typecheck_workers = Server::WorkerProcess.start_typecheck_workers(steepfile: steepfile, count: 1, args: []) master = Server::Master.new( project: project, @@ -607,8 +607,8 @@ def test_signature_type_check project = Project.new(steepfile_path: steepfile) Project::DSL.parse(project, steepfile.read) - interaction_worker = Server::WorkerProcess.spawn_worker(:interaction, name: "interaction", steepfile: steepfile) - typecheck_workers = Server::WorkerProcess.spawn_typecheck_workers(steepfile: steepfile, count: 1, args: []) + interaction_worker = Server::WorkerProcess.start_worker(:interaction, name: "interaction", steepfile: steepfile) + typecheck_workers = Server::WorkerProcess.start_typecheck_workers(steepfile: steepfile, count: 1, args: []) master = Server::Master.new(project: project, reader: worker_reader, @@ -681,8 +681,8 @@ def test_code_interaction project = Project.new(steepfile_path: steepfile) Project::DSL.parse(project, steepfile.read) - interaction_worker = Server::WorkerProcess.spawn_worker(:interaction, name: "interaction", steepfile: steepfile) - typecheck_workers = Server::WorkerProcess.spawn_typecheck_workers(steepfile: steepfile, count: 2, args: []) + interaction_worker = Server::WorkerProcess.start_worker(:interaction, name: "interaction", steepfile: steepfile) + typecheck_workers = Server::WorkerProcess.start_typecheck_workers(steepfile: steepfile, count: 2, args: []) master = Server::Master.new(project: project, reader: worker_reader, @@ -731,8 +731,8 @@ def test_workspace_symbol project = Project.new(steepfile_path: steepfile) Project::DSL.parse(project, steepfile.read) - interaction_worker = Server::WorkerProcess.spawn_worker(:interaction, name: "interaction", steepfile: steepfile) - typecheck_workers = Server::WorkerProcess.spawn_typecheck_workers(steepfile: steepfile, count: 2, args: []) + interaction_worker = Server::WorkerProcess.start_worker(:interaction, name: "interaction", steepfile: steepfile) + typecheck_workers = Server::WorkerProcess.start_typecheck_workers(steepfile: steepfile, count: 2, args: []) master = Server::Master.new(project: project, reader: worker_reader, From f9ebea42fe7883f3f5d841e2cd18aa0ac02ea308 Mon Sep 17 00:00:00 2001 From: Soutaro Matsumoto Date: Mon, 24 Oct 2022 11:36:38 +0900 Subject: [PATCH 6/6] Start worker process by `fork` if available --- lib/steep/server/master.rb | 5 +- lib/steep/server/worker_process.rb | 92 +++++++++++++++++++++++++---- sig/steep/server/worker_process.rbs | 23 +++++++- 3 files changed, 107 insertions(+), 13 deletions(-) diff --git a/lib/steep/server/master.rb b/lib/steep/server/master.rb index 34b25c800..ba1dfc417 100644 --- a/lib/steep/server/master.rb +++ b/lib/steep/server/master.rb @@ -796,7 +796,10 @@ def start_type_check(request, last_request:, start_progress:) Steep.logger.info "Sending $/typecheck/start notifications" typecheck_workers.each do |worker| - assignment = Services::PathAssignment.new(max_index: typecheck_workers.size, index: worker.index) + assignment = Services::PathAssignment.new( + max_index: typecheck_workers.size, + index: worker.index || raise + ) job_queue << SendMessageJob.to_worker( worker, diff --git a/lib/steep/server/worker_process.rb b/lib/steep/server/worker_process.rb index 2e797ac68..2271b4c6e 100644 --- a/lib/steep/server/worker_process.rb +++ b/lib/steep/server/worker_process.rb @@ -18,25 +18,97 @@ def initialize(reader:, writer:, stderr:, wait_thread:, name:, index: nil) @index = index end - def self.start_worker(type, name:, steepfile:, steep_command: "steep", options: [], delay_shutdown: false, index: nil) + def self.start_worker(type, name:, steepfile:, steep_command: "steep", index: nil, delay_shutdown: false, patterns: []) + begin + fork_worker( + type, + name: name, + steepfile: steepfile, + index: index, + delay_shutdown: delay_shutdown, + patterns: patterns + ) + rescue NotImplementedError + spawn_worker( + type, + name: name, + steepfile: steepfile, + steep_command: steep_command, + index: index, + delay_shutdown: delay_shutdown, + patterns: patterns + ) + end + end + + def self.fork_worker(type, name:, steepfile:, index:, delay_shutdown:, patterns:) + stdin_in, stdin_out = IO.pipe + stdout_in, stdout_out = IO.pipe + + worker = Drivers::Worker.new(stdout: stdout_out, stdin: stdin_in, stderr: STDERR) + + worker.steepfile = steepfile + worker.worker_type = type + worker.worker_name = name + worker.delay_shutdown = delay_shutdown + if (max, this = index) + worker.max_index = max + worker.index = this + end + worker.commandline_args = patterns + + pid = fork do + worker.run() + end + + pid or raise + + writer = LanguageServer::Protocol::Transport::Io::Writer.new(stdin_out) + reader = LanguageServer::Protocol::Transport::Io::Reader.new(stdout_in) + + # @type var wait_thread: Thread & _ProcessWaitThread + wait_thread = _ = Thread.new { Process.waitpid(pid) } + wait_thread.define_singleton_method(:pid) { pid } + + stdin_in.close + stdout_out.close + + new( + reader: reader, + writer: writer, + stderr: STDERR, + wait_thread: wait_thread, + name: name, + index: index&.[](1) + ) + end + + def self.spawn_worker(type, name:, steepfile:, steep_command:, index:, delay_shutdown:, patterns:) args = ["--name=#{name}", "--steepfile=#{steepfile}"] args << (%w(debug info warn error fatal unknown)[Steep.logger.level].yield_self {|log_level| "--log-level=#{log_level}" }) + if Steep.log_output.is_a?(String) args << "--log-output=#{Steep.log_output}" end + + if (max, this = index) + args << "--max-index=#{max}" + args << "--index=#{this}" + end + + if delay_shutdown + args << "--delay-shutdown" + end + command = case type when :interaction - [steep_command, "worker", "--interaction", *args, *options] + [steep_command, "worker", "--interaction", *args, *patterns] when :typecheck - [steep_command, "worker", "--typecheck", *args, *options] + [steep_command, "worker", "--typecheck", *args, *patterns] else raise "Unknown type: #{type}" end - if delay_shutdown - command << "--delay-shutdown" - end - stdin, stdout, thread = if Gem.win_platform? __skip__ = Open3.popen2(*command, new_pgroup: true) else @@ -47,7 +119,7 @@ def self.start_worker(type, name:, steepfile:, steep_command: "steep", options: writer = LanguageServer::Protocol::Transport::Io::Writer.new(stdin) reader = LanguageServer::Protocol::Transport::Io::Reader.new(stdout) - new(reader: reader, writer: writer, stderr: stderr, wait_thread: thread, name: name, index: index) + new(reader: reader, writer: writer, stderr: stderr, wait_thread: thread, name: name, index: index&.[](1)) end def self.start_typecheck_workers(steepfile:, args:, steep_command: "steep", count: [Etc.nprocessors - 1, 1].max, delay_shutdown: false) @@ -57,9 +129,9 @@ def self.start_typecheck_workers(steepfile:, args:, steep_command: "steep", coun name: "typecheck@#{i}", steepfile: steepfile, steep_command: steep_command, - options: ["--max-index=#{count}", "--index=#{i}", *args], + index: [count, i], + patterns: args, delay_shutdown: delay_shutdown, - index: i ) end end diff --git a/sig/steep/server/worker_process.rbs b/sig/steep/server/worker_process.rbs index 9a78ced9c..ac11ae6d9 100644 --- a/sig/steep/server/worker_process.rbs +++ b/sig/steep/server/worker_process.rbs @@ -49,9 +49,28 @@ module Steep name: String, steepfile: Pathname, ?steep_command: ::String, - ?options: Array[String], + ?patterns: Array[String], ?delay_shutdown: bool, - ?index: Integer? + ?index: [Integer, Integer]? + ) -> WorkerProcess + + def self.fork_worker: ( + worker_type `type`, + name: String, + steepfile: Pathname, + patterns: Array[String], + delay_shutdown: bool, + index: [Integer, Integer]? + ) -> WorkerProcess + + def self.spawn_worker: ( + worker_type `type`, + name: String, + steepfile: Pathname, + steep_command: ::String, + patterns: Array[String], + delay_shutdown: bool, + index: [Integer, Integer]? ) -> WorkerProcess def self.start_typecheck_workers: (