Skip to content

Commit

Permalink
Heavily reduce asyncjob timeouts and do not rely on timeout timer to …
Browse files Browse the repository at this point in the history
…fire
  • Loading branch information
xPaw committed Oct 30, 2023
1 parent 75d1c5f commit 749533f
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 35 deletions.
2 changes: 1 addition & 1 deletion SteamKit2/SteamKit2/Steam/SteamClient/AsyncJobManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ public void SetTimeoutsEnabled( bool enable )
/// <summary>
/// This is called periodically to cancel and clear out any jobs that have timed out (no response from Steam).
/// </summary>
void CancelTimedoutJobs()
internal void CancelTimedoutJobs()
{
// ConcurrentDictionary.Values performs a full copy, so this iteration is safe
// see: http://referencesource.microsoft.com/#mscorlib/system/Collections/Concurrent/ConcurrentDictionary.cs,fe55c11912af21d2
Expand Down
65 changes: 31 additions & 34 deletions SteamKit2/Tests/AsyncJobFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -59,12 +59,12 @@ public void AsyncJobClearsOnCompletion()
public async Task AsyncJobClearsOnTimeout()
{
SteamClient client = new SteamClient();
client.jobManager.SetTimeoutsEnabled( true );

AsyncJob<Callback> asyncJob = new AsyncJob<Callback>( client, 123 );
asyncJob.Timeout = TimeSpan.FromSeconds( 1 );
asyncJob.Timeout = TimeSpan.FromMilliseconds( 50 );

await Task.Delay( TimeSpan.FromSeconds( 5 ) );
await Task.Delay( asyncJob.Timeout );
client.jobManager.CancelTimedoutJobs();

Assert.False( client.jobManager.asyncJobs.ContainsKey( asyncJob ), "Async job dictionary should no longer contain jobid key after timeout" );
Assert.False( client.jobManager.asyncJobs.ContainsKey( 123 ), "Async job dictionary should no longer contain jobid key (as value type) after timeout" );
Expand Down Expand Up @@ -106,18 +106,18 @@ public async Task AsyncJobGivesBackCallback()
public async Task AsyncJobTimesout()
{
SteamClient client = new SteamClient();
client.jobManager.SetTimeoutsEnabled( true );

AsyncJob<Callback> asyncJob = new AsyncJob<Callback>( client, 123 );
asyncJob.Timeout = TimeSpan.FromSeconds( 1 );
asyncJob.Timeout = TimeSpan.FromMilliseconds( 50 );

Task<Callback> asyncTask = asyncJob.ToTask();

await Task.Delay( TimeSpan.FromSeconds( 5 ) );
await Task.Delay( asyncJob.Timeout );
client.jobManager.CancelTimedoutJobs();

Assert.True( asyncTask.IsCompleted, "Async job should be completed after 5 seconds of a 1 second job timeout" );
Assert.True( asyncTask.IsCanceled, "Async job should be canceled after 5 seconds of a 1 second job timeout" );
Assert.False( asyncTask.IsFaulted, "Async job should not be faulted after 5 seconds of a 1 second job timeout" );
Assert.True( asyncTask.IsCompleted, "Async job should be completed yet" );
Assert.True( asyncTask.IsCanceled, "Async job should be canceled yet" );
Assert.False( asyncTask.IsFaulted, "Async job should not be faulted yet" );

await Assert.ThrowsAsync<TaskCanceledException>( async () => await asyncTask );
}
Expand Down Expand Up @@ -205,12 +205,12 @@ public void AsyncJobMultipleClearsOnCompletion()
public async Task AsyncJobMultipleClearsOnTimeout()
{
SteamClient client = new SteamClient();
client.jobManager.SetTimeoutsEnabled( true );

AsyncJobMultiple<Callback> asyncJob = new AsyncJobMultiple<Callback>( client, 123, ccall => true );
asyncJob.Timeout = TimeSpan.FromSeconds( 1 );
asyncJob.Timeout = TimeSpan.FromMilliseconds( 50 );

await Task.Delay( TimeSpan.FromSeconds( 5 ) );
await Task.Delay( asyncJob.Timeout );
client.jobManager.CancelTimedoutJobs();

Assert.False( client.jobManager.asyncJobs.ContainsKey( asyncJob ), "Async job dictionary should no longer contain jobid key after timeout" );
Assert.False( client.jobManager.asyncJobs.ContainsKey( 123 ), "Async job dictionary should no longer contain jobid key (as value type) after timeout" );
Expand All @@ -220,31 +220,29 @@ public async Task AsyncJobMultipleClearsOnTimeout()
public async Task AsyncJobMultipleExtendsTimeoutOnMessage()
{
SteamClient client = new SteamClient();
client.jobManager.SetTimeoutsEnabled( true );

AsyncJobMultiple<Callback> asyncJob = new AsyncJobMultiple<Callback>( client, 123, call => call.IsFinished );
asyncJob.Timeout = TimeSpan.FromSeconds( 5 );
asyncJob.Timeout = TimeSpan.FromMilliseconds( 50 );

Task<AsyncJobMultiple<Callback>.ResultSet> asyncTask = asyncJob.ToTask();

// wait 3 seconds before we post any results to this job at all
await Task.Delay( TimeSpan.FromSeconds( 3 ) );

// we should not be completed or canceled yet
Assert.False( asyncTask.IsCompleted, "AsyncJobMultiple should not be completed after 3 seconds of 5 second timeout" );
Assert.False( asyncTask.IsCanceled, "AsyncJobMultiple should not be canceled after 3 seconds of 5 second timeout" );
Assert.False( asyncTask.IsFaulted, "AsyncJobMultiple should not be faulted after 3 econds of 5 second timeout" );
Assert.False( asyncTask.IsCompleted, "AsyncJobMultiple should not be completed yet" );
Assert.False( asyncTask.IsCanceled, "AsyncJobMultiple should not be canceled yet" );
Assert.False( asyncTask.IsFaulted, "AsyncJobMultiple should not be faulted yet" );

// give result 1 of 2
asyncJob.AddResult( new Callback { JobID = 123, IsFinished = false } );

// delay for what the original timeout would have been
await Task.Delay( TimeSpan.FromSeconds( 5 ) );
await Task.Delay( TimeSpan.FromMilliseconds( 50 ) );

client.jobManager.CancelTimedoutJobs();

// we still shouldn't be completed or canceled (timed out)
Assert.False( asyncTask.IsCompleted, "AsyncJobMultiple should not be completed 5 seconds after a result was added (result should extend timeout)" );
Assert.False( asyncTask.IsCanceled, "AsyncJobMultiple should not be canceled 5 seconds after a result was added (result should extend timeout)" );
Assert.False( asyncTask.IsFaulted, "AsyncJobMultiple should not be faulted 5 seconds aftr a result was added (result should extend timeout)" );
Assert.False( asyncTask.IsCompleted, "AsyncJobMultiple should not be completed yet after result was added (result should extend timeout)" );
Assert.False( asyncTask.IsCanceled, "AsyncJobMultiple should not be canceled yet after result was added (result should extend timeout)" );
Assert.False( asyncTask.IsFaulted, "AsyncJobMultiple should not be faulted yet after a result was added (result should extend timeout)" );

asyncJob.AddResult( new Callback { JobID = 123, IsFinished = true } );

Expand All @@ -258,18 +256,18 @@ public async Task AsyncJobMultipleExtendsTimeoutOnMessage()
public async Task AsyncJobMultipleTimesout()
{
SteamClient client = new SteamClient();
client.jobManager.SetTimeoutsEnabled( true );

AsyncJobMultiple<Callback> asyncJob = new AsyncJobMultiple<Callback>( client, 123, call => false );
asyncJob.Timeout = TimeSpan.FromSeconds( 1 );
asyncJob.Timeout = TimeSpan.FromMilliseconds( 50 );

Task<AsyncJobMultiple<Callback>.ResultSet> asyncTask = asyncJob.ToTask();

await Task.Delay( TimeSpan.FromSeconds( 5 ) );
await Task.Delay( asyncJob.Timeout );
client.jobManager.CancelTimedoutJobs();

Assert.True( asyncTask.IsCompleted, "AsyncJobMultiple should be completed after 5 seconds of a 1 second job timeout" );
Assert.True( asyncTask.IsCanceled, "AsyncJobMultiple should be canceled after 5 seconds of a 1 second job timeout" );
Assert.False( asyncTask.IsFaulted, "AsyncJobMultiple should not be faulted after 5 seconds of a 1 second job timeout" );
Assert.True( asyncTask.IsCompleted, "AsyncJobMultiple should be completed after job timeout" );
Assert.True( asyncTask.IsCanceled, "AsyncJobMultiple should be canceled after job timeout" );
Assert.False( asyncTask.IsFaulted, "AsyncJobMultiple should not be faulted after job timeout" );

await Assert.ThrowsAsync<TaskCanceledException>( async () => await asyncTask );
}
Expand All @@ -278,7 +276,6 @@ public async Task AsyncJobMultipleTimesout()
public async Task AsyncJobMultipleCompletesOnIncompleteResult()
{
SteamClient client = new SteamClient();
client.jobManager.SetTimeoutsEnabled( true );

AsyncJobMultiple<Callback> asyncJob = new AsyncJobMultiple<Callback>( client, 123, call => call.IsFinished );
asyncJob.Timeout = TimeSpan.FromSeconds( 1 );
Expand All @@ -290,9 +287,10 @@ public async Task AsyncJobMultipleCompletesOnIncompleteResult()
asyncJob.AddResult( onlyResult );

// adding a result will extend the job's timeout, but we'll cheat here and decrease it
asyncJob.Timeout = TimeSpan.FromSeconds( 1 );
asyncJob.Timeout = TimeSpan.FromMilliseconds( 50 );

await Task.Delay( TimeSpan.FromSeconds( 5 ) );
await Task.Delay( asyncJob.Timeout );
client.jobManager.CancelTimedoutJobs();

Assert.True( asyncTask.IsCompleted, "AsyncJobMultiple should be completed on partial (timed out) result set" );
Assert.False( asyncTask.IsCanceled, "AsyncJobMultiple should not be canceled on partial (timed out) result set" );
Expand All @@ -310,7 +308,6 @@ public async Task AsyncJobMultipleCompletesOnIncompleteResult()
public async Task AsyncJobMultipleCompletesOnIncompleteResultAndFailure()
{
SteamClient client = new SteamClient();
client.jobManager.SetTimeoutsEnabled( true );

AsyncJobMultiple<Callback> asyncJob = new AsyncJobMultiple<Callback>( client, 123, call => call.IsFinished );
asyncJob.Timeout = TimeSpan.FromSeconds( 1 );
Expand Down

0 comments on commit 749533f

Please sign in to comment.