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

Stop throwing an exception in the finally of WithTimeouts #563

Merged
merged 1 commit into from
Dec 4, 2023

Conversation

nathanwoctopusdeploy
Copy link
Contributor

@nathanwoctopusdeploy nathanwoctopusdeploy commented Nov 30, 2023

Background

Stop throwing an exception in the finally of WithTimeouts when the Stream is in an error state.

[sc-65700]

This has been run through a Tentacle build here OctopusDeploy/OctopusTentacle#711

How to review this PR

Quality ✔️

Pre-requisites

  • I have read How we use GitHub Issues for help deciding when and where it's appropriate to make an issue.
  • I have considered informing or consulting the right people, according to the ownership map.
  • I have considered appropriate testing for my change.

…am is in an error state and potentially hide / rethrow the original error causing confusion about the source of the error.
@nathanwoctopusdeploy nathanwoctopusdeploy marked this pull request as ready for review December 2, 2023 12:52
@nathanwoctopusdeploy nathanwoctopusdeploy requested a review from a team as a code owner December 2, 2023 12:52
stream.WriteTimeout = currentWriteTimeout;
try
{
stream.ReadTimeout = currentReadTimeout;
Copy link
Contributor

@sburmanoctopus sburmanoctopus Dec 3, 2023

Choose a reason for hiding this comment

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

🤔 Just wondering, do other native .NET streams throw an exception when adjusting the Read/Write timeouts?

If not, then I wonder if an alternative would be to instead change the NetworkTimeoutStream to not throw an exception when changing ReadTimeout or WriteTimeout.

The current solution will be more generally safe, as it guarantees any read/write timeout alteration won't get in the way. But I couldn't help but wonder if we were guarding against something that shouldn't happen (and we got read/write timeout properties in NetworkTimeoutStream wrong instead).

Copy link
Contributor Author

@nathanwoctopusdeploy nathanwoctopusdeploy Dec 3, 2023

Choose a reason for hiding this comment

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

If not, then I wonder if an alternative would be to instead change the NetworkTimeoutStream to not throw an exception when changing ReadTimeout or WriteTimeout.

It's up to the underlying stream and if it's a network stream, possibly the OS (maybe, I don't really know ;) )? I think they do throw if the stream is not usable, and you throw an unrelated, side effect error, hence why we wrapped it and rethrow the real error.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

If NetworkTimeoutStream doesn't throw, then do we risk getting into a situation where we swallow real errors and end up not correctly changing timeouts, but we think we have.

}
}

if (!timeoutsReverted)
Copy link
Contributor

Choose a reason for hiding this comment

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

Is timeoutsReverted what we want?

If await func() succeeds, but Read/Write timeout throw an exception, then timeoutsReverted will be false, and we will throw an InvalidOperationException here. But I thought the point of this PR was to stop throwing an exception in the finally. I.e., aren't we still throwing an exception, just a different one?

I'm likely not understanding something...

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 should not happen.

This was a fail safe to make sure it is working as I expected e.g. we throw so it doesn't matter that the timeouts were not reverted.

I didn't want to swallow errors setting the timeouts when it was a real issue, e.g. the actual call has not thrown, but for some reason the set timeouts throws. That should never happen.

Copy link
Contributor Author

@nathanwoctopusdeploy nathanwoctopusdeploy Dec 3, 2023

Choose a reason for hiding this comment

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

If await func() succeeds, but Read/Write timeout throw an exception

Should this happen? Is it valid? Will it leave us in a weird state if it did happen

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah, I see. The subtilty is that if we set the read/write timeout, and it throws a timeout exception, then this only really happens because it would have already thrown an exception with await func().

Yep, that makes sense 🙂

Copy link
Contributor

@sburmanoctopus sburmanoctopus left a comment

Choose a reason for hiding this comment

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

I'd like to understand the question on timeoutsReverted and why we want to throw an exception first before approving.

Copy link
Contributor

@sburmanoctopus sburmanoctopus left a comment

Choose a reason for hiding this comment

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

LGTM

@nathanwoctopusdeploy
Copy link
Contributor Author

nathanwoctopusdeploy commented Dec 3, 2023

I'd like to understand the question on timeoutsReverted and why we want to throw an exception first before approving.

There may be a better approach to this. Happy to pair and revisit @sburmanoctopus . The general idea was don't set the timeouts when we can't as we are in error but don't hide errors and allow this to be an area that could cause bugs.

I considered changing the NetworkTimeoutStream but I didn't feel this was safe to do. I think the logic we are using to change the timeout is the correct place, e.g. the caller that causes the error should be responsible for handling it.

We could make it more advanced and determine when / when we cannot change timeouts based on the state of a stream. I went for try/catch/ensure we are not hiding real issues.

@nathanwoctopusdeploy nathanwoctopusdeploy merged commit 0d8ea76 into main Dec 4, 2023
15 checks passed
@nathanwoctopusdeploy nathanwoctopusdeploy deleted the sast/fix-withtimeouts-finally-bug branch December 4, 2023 23:42
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