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

fix: Prevent exception on return of job ID to disposed pool #48

Merged
merged 6 commits into from
Feb 28, 2024

Conversation

mycroes
Copy link
Owner

@mycroes mycroes commented Nov 30, 2023

Currently when the connection is disposed and requests are still in the queue they will except because the job ID can no longer be returned to the pool. Making the exception on ReturnJobId conditional on a new _disposed flag prevents the exception from being thrown, but it does permit 'successful' returns to a disposed pool.

@gfoidl please let me know what you think. This is hitting us in production now, so I'll probably merge this quickly.

@mycroes
Copy link
Owner Author

mycroes commented Nov 30, 2023

@gfoidl No need to hurry, hotfixed the previous release, because there's some unreleased changes on main anyway.

gfoidl
gfoidl previously approved these changes Nov 30, 2023
Copy link
Collaborator

@gfoidl gfoidl left a comment

Choose a reason for hiding this comment

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

Nice and simple solution.

Makes sense!

Sally7/RequestExecutor/ConcurrentRequestExecutor.cs Outdated Show resolved Hide resolved
@mycroes
Copy link
Owner Author

mycroes commented Nov 30, 2023

Thanks @gfoidl, appreciate your opinion a lot. I intend to add some unit tests for this behavior as well, so I'm not merging straight away.


public ValueTask<int> RentJobIdAsync(CancellationToken cancellationToken) => _jobIdPool.Reader.ReadAsync(cancellationToken);

public void ReturnJobId(int jobId)
{
if (!_jobIdPool.Writer.TryWrite(jobId))
if (!_jobIdPool.Writer.TryWrite(jobId) && !Volatile.Read(ref _disposed))
Copy link
Contributor

Choose a reason for hiding this comment

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

Is there a reason for the ordering? Wouldn't you want the !Volatile.Read(ref _disposed) checked first, and the TryWrite only executed if it isn't yet disposed, taking care of short-circuiting &&.

Or is there a reason for always executing the writing to the jobIdPool, independent of it being disposed or not?

Copy link
Collaborator

Choose a reason for hiding this comment

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

TryWrite is called more often than Dispose so I think that order is fine, meaning that the common path comes first.
If TryWrite fails, then it's checked if disposed or not.

But TBH I don't think that any order here actually matters. The arguing of @scamille is also fine.
Both yield the same result, and perf-wise there's no difference (at least with TCP connection to PLC in mind). And I have no problem if the order is flipped.

Copy link
Owner Author

Choose a reason for hiding this comment

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

There's also the hypothetical race condition of _disposed not yet being set when it's read, but the TryWrite failing because the writer had been Complete()-ed in the meantime (assuming the Volatile.Read would come first). I'm not sure if there's anything in .NET that rules out this race condition, but this ordering should prevent it either way.

@mycroes mycroes force-pushed the job-pool-exception-on-dispose branch from 9b237ba to 4b335b0 Compare February 28, 2024 19:39
@mycroes mycroes merged commit cc1c04a into main Feb 28, 2024
3 checks passed
@mycroes mycroes deleted the job-pool-exception-on-dispose branch February 28, 2024 19: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.

3 participants