Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure runner id is safe for filenames & implement wait_for_connectivity #19

Merged
merged 4 commits into from
Dec 6, 2023

Conversation

benjaminwood
Copy link
Contributor

We discovered a scenario where things would hang if the transport crashed before it could open the write pipe. This commit adds a wait_for_connectivity method that will wait for the transport to open the pipe for writing. If it doesn't happen within 5 seconds, the controller will exit.

We also discovered that the runner id could contain characters that are not allowed in filenames. This commit adds a safe_filename method that will strip out any characters that are not allowed in filenames.

We discovered a scenario where things would hang if the transport
crashed before it could open the write pipe. This commit adds a
wait_for_connectivity method that will wait for the transport to
open the pipe for writing. If it doesn't happen within 5 seconds,
the controller will exit.

We also discovered that the runner id could contain characters
that are not allowed in filenames. This commit adds a safe_filename
method that will strip out any characters that are not allowed in
filenames.
@benjaminwood benjaminwood self-assigned this Dec 3, 2023
@@ -10,6 +10,7 @@
before do
allow(Process).to receive(:spawn).and_return(123)
allow(controller).to receive(:handle_termination_signals)
allow(controller).to receive(:wait_for_connectivity)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a tricky method to test because it contains a blocking read that'll screw up the test run if we let it. Open to ideas about how we can test it. It is tested implicitly by running the tests with selective so 🤷🏻

@@ -66,8 +67,6 @@ def init_logger(enabled)
def run_main_loop
loop do
message = pipe.read
next sleep(0.1) if message.nil? || message.empty?
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm removing this from run_main_loop because so far I've only been able to observe the nil message when we're starting up. I believe this happens when we're waiting for the transport to open the pipe for writing.

At one point in the past I observed receiving both nil and "" (empty string) multiple times, not just at initialization. But, I wasn't able to reproduce that here, so I think we need to rediscover what scenario causes that (if any). We should certainly do some more manual testing with this before release.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, note that the handling of the initial nil has been moved to wait_for connectivity.

Comment on lines +299 to +304
def safe_filename(filename)
filename
.gsub(/[\/\\:*?"<>|\n\r]+/, '_')
.gsub(/^\.+|\.+$/, '')
.strip[0, 255]
end
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This handles runner_ids like foo/bar that wouldn't otherwise be suitable for the pipe filename.

next sleep(0.1) if message.nil?

response = JSON.parse(message, symbolize_names: true)
@connectivity = true if response[:command] == "connected"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is to be paired with a change in the backend that sends the "connected" command as soon as the socket connects.

benjaminwood and others added 2 commits December 4, 2023 23:59
Co-authored-by: Nate Vick <nate.vick@hint.io>
Co-authored-by: Nate Vick <nate.vick@hint.io>
@benjaminwood benjaminwood force-pushed the handle-early-transport-crashes branch 2 times, most recently from d937ed4 to bf1fc70 Compare December 6, 2023 00:11
We havne't been able to reproduce it locally or in test, but it's
happened on CI. See:

/lib/selective/ruby/core/named_pipe.rb:38:in `write': closed stream (IOError)
	selective-ruby-core-71005fe4776b/lib/selective/ruby/core/named_pipe.rb:38:in `write'
	selective-ruby-core-71005fe4776b/lib/selective/ruby/core/controller.rb:193:in `kill_transport'
	selective-ruby-core-71005fe4776b/lib/selective/ruby/core/controller.rb:162:in `block in wait_for_connectivity'

Co-authored-by: Nate Vick <nate.vick@hint.io>
@benjaminwood benjaminwood marked this pull request as ready for review December 6, 2023 00:19
Copy link
Contributor

@natevick natevick left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit: 🚀

@natevick natevick merged commit 0828e7c into main Dec 6, 2023
4 checks passed
@natevick natevick deleted the handle-early-transport-crashes branch December 6, 2023 00:20
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants