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

Change nodejs waiting on pipes to not panic #13689

Merged
merged 1 commit into from
Sep 3, 2023
Merged

Conversation

Frassle
Copy link
Member

@Frassle Frassle commented Aug 9, 2023

Description

Hit this while testing with matrix testing. Fairly frequently the go routine waiting for pipesDone would try to write to the response channel and panic because it was already closed.

This rewrites the method to only use the response channel for the running program, and we just explictly wait on all three events (pipes, handle, program) and return the first one that triggers.

Also it refactors execNodejs to just be a sync method that returns the response. The management of that running in a goroutine and writing to a channel is just kept in Run.

Checklist

  • I have run make tidy to update any new dependencies
  • I have run make lint to verify my code passes the lint check
    • I have formatted my code using gofumpt
  • I have added tests that prove my fix is effective or that my feature works - Current tests should cover current use of this, and matrix testing will verify that this fix is in place for that.
  • I have run make changelog and committed the changelog/pending/<file> documenting my change
  • Yes, there are changes in this PR that warrants bumping the Pulumi Cloud API version

@pulumi-bot
Copy link
Contributor

pulumi-bot commented Aug 9, 2023

Changelog

[uncommitted] (2023-09-02)

Bug Fixes

  • [sdk/nodejs] Fix a possible panic in running NodeJS programs.
    #13689

@Frassle Frassle requested a review from a team August 10, 2023 10:49
Copy link
Contributor

@abhinav abhinav left a comment

Choose a reason for hiding this comment

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

This is a positive change, although it still has a risk of panic. Suggested a fix.

// Channel producing the final response we want to issue to our caller. Will get the result of
// the actual nodejs process we launch, or any results caused by errors in our server/pipes.
responseChannel := make(chan *pulumirpc.RunResponse)
defer close(responseChannel)
Copy link
Contributor

Choose a reason for hiding this comment

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

This will still panic if execNodeJs finishes after pipesDone or handle.Done return an error because that'll exit this function, closing this channel, and then the goroutine will attempt to write to a closed channel, panic, and kill the process.

This can be fixed by using a channel with a buffer of one and dropping the defer close(responseChannel). Let the channel be GCed if this function returns with an error. This function is short-lived, so that's not a big deal.

Another alternative is to use the channel just to signal that execNodeJs is done, but store the value in a variable in the scope:

var response *pulumirpc.RunRespnse
haveResponse := make(chan struct{})
go func() {
  defer close(haveResponse)
  response = ...
}()

This way, the channel will always be closed when execNodeJs finishes.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good spot, it looks like we can just move the close inside the goroutine to fix this as well?

Comment on lines -578 to -579
func (host *nodeLanguageHost) execNodejs(ctx context.Context,
responseChannel chan<- *pulumirpc.RunResponse, req *pulumirpc.RunRequest,
Copy link
Contributor

Choose a reason for hiding this comment

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

Good call on removing the channel from the function contract here completely.
@dixler was lamenting about something like the problem that caused this panic recently in the context of channels.

Hit this while testing with matrix testing. Fairly frequently the go
routine waiting for `pipesDone` would try to write to the response
channel and panic because it was already closed.

This rewrites the method to only use the response channel for the
running program, and we just explictly wait on all three events (pipes,
handle, program) and return the first one that triggers.

Also it refactors execNodejs to just be a sync method that returns the
response. The management of that running in a goroutine and writing to a
channel is just kept in Run.
@Frassle Frassle added this pull request to the merge queue Sep 3, 2023
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Sep 3, 2023
@Frassle Frassle added this pull request to the merge queue Sep 3, 2023
Merged via the queue into master with commit 33715ad Sep 3, 2023
45 checks passed
@Frassle Frassle deleted the fraser/nodejsAwaitRun branch September 3, 2023 07:59
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.

None yet

3 participants