diff --git a/lib/ruby_lsp/ruby_lsp_rails/runner_client.rb b/lib/ruby_lsp/ruby_lsp_rails/runner_client.rb index 642eeb25..8ff76363 100644 --- a/lib/ruby_lsp/ruby_lsp_rails/runner_client.rb +++ b/lib/ruby_lsp/ruby_lsp_rails/runner_client.rb @@ -41,6 +41,7 @@ class EmptyMessageError < StandardError; end sig { void } def initialize + @mutex = T.let(Mutex.new, Mutex) # Spring needs a Process session ID. It uses this ID to "attach" itself to the parent process, so that when the # parent ends, the spring process ends as well. If this is not set, Spring will throw an error while trying to # set its own session ID @@ -176,7 +177,9 @@ def send_message(request, params = nil) message[:params] = params if params json = message.to_json - @stdin.write("Content-Length: #{json.length}\r\n\r\n", json) + @mutex.synchronize do + @stdin.write("Content-Length: #{json.length}\r\n\r\n", json) + end rescue Errno::EPIPE # The server connection died end @@ -187,13 +190,16 @@ def send_notification(request, params = nil) = send_message(request, params) sig { overridable.returns(T.nilable(T::Hash[Symbol, T.untyped])) } def read_response - headers = @stdout.gets("\r\n\r\n") - raise IncompleteMessageError unless headers + raw_response = @mutex.synchronize do + headers = @stdout.gets("\r\n\r\n") + raise IncompleteMessageError unless headers + + content_length = headers[/Content-Length: (\d+)/i, 1].to_i + raise EmptyMessageError if content_length.zero? - content_length = headers[/Content-Length: (\d+)/i, 1].to_i - raise EmptyMessageError if content_length.zero? + @stdout.read(content_length) + end - raw_response = @stdout.read(content_length) response = JSON.parse(T.must(raw_response), symbolize_names: true) if response[:error]