From 749533f06d44ffe29c543dc1affe416cc7f4310f Mon Sep 17 00:00:00 2001 From: Pavel Djundik Date: Sun, 29 Oct 2023 12:05:05 +0200 Subject: [PATCH] Heavily reduce asyncjob timeouts and do not rely on timeout timer to fire --- .../Steam/SteamClient/AsyncJobManager.cs | 2 +- SteamKit2/Tests/AsyncJobFacts.cs | 65 +++++++++---------- 2 files changed, 32 insertions(+), 35 deletions(-) diff --git a/SteamKit2/SteamKit2/Steam/SteamClient/AsyncJobManager.cs b/SteamKit2/SteamKit2/Steam/SteamClient/AsyncJobManager.cs index 13b2c6c7c..bea57760f 100644 --- a/SteamKit2/SteamKit2/Steam/SteamClient/AsyncJobManager.cs +++ b/SteamKit2/SteamKit2/Steam/SteamClient/AsyncJobManager.cs @@ -123,7 +123,7 @@ public void SetTimeoutsEnabled( bool enable ) /// /// This is called periodically to cancel and clear out any jobs that have timed out (no response from Steam). /// - 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 diff --git a/SteamKit2/Tests/AsyncJobFacts.cs b/SteamKit2/Tests/AsyncJobFacts.cs index 6dc7703d2..3bca5abe2 100644 --- a/SteamKit2/Tests/AsyncJobFacts.cs +++ b/SteamKit2/Tests/AsyncJobFacts.cs @@ -59,12 +59,12 @@ public void AsyncJobClearsOnCompletion() public async Task AsyncJobClearsOnTimeout() { SteamClient client = new SteamClient(); - client.jobManager.SetTimeoutsEnabled( true ); AsyncJob asyncJob = new AsyncJob( 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" ); @@ -106,18 +106,18 @@ public async Task AsyncJobGivesBackCallback() public async Task AsyncJobTimesout() { SteamClient client = new SteamClient(); - client.jobManager.SetTimeoutsEnabled( true ); AsyncJob asyncJob = new AsyncJob( client, 123 ); - asyncJob.Timeout = TimeSpan.FromSeconds( 1 ); + asyncJob.Timeout = TimeSpan.FromMilliseconds( 50 ); Task 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( async () => await asyncTask ); } @@ -205,12 +205,12 @@ public void AsyncJobMultipleClearsOnCompletion() public async Task AsyncJobMultipleClearsOnTimeout() { SteamClient client = new SteamClient(); - client.jobManager.SetTimeoutsEnabled( true ); AsyncJobMultiple asyncJob = new AsyncJobMultiple( 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" ); @@ -220,31 +220,29 @@ public async Task AsyncJobMultipleClearsOnTimeout() public async Task AsyncJobMultipleExtendsTimeoutOnMessage() { SteamClient client = new SteamClient(); - client.jobManager.SetTimeoutsEnabled( true ); AsyncJobMultiple asyncJob = new AsyncJobMultiple( client, 123, call => call.IsFinished ); - asyncJob.Timeout = TimeSpan.FromSeconds( 5 ); + asyncJob.Timeout = TimeSpan.FromMilliseconds( 50 ); Task.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 } ); @@ -258,18 +256,18 @@ public async Task AsyncJobMultipleExtendsTimeoutOnMessage() public async Task AsyncJobMultipleTimesout() { SteamClient client = new SteamClient(); - client.jobManager.SetTimeoutsEnabled( true ); AsyncJobMultiple asyncJob = new AsyncJobMultiple( client, 123, call => false ); - asyncJob.Timeout = TimeSpan.FromSeconds( 1 ); + asyncJob.Timeout = TimeSpan.FromMilliseconds( 50 ); Task.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( async () => await asyncTask ); } @@ -278,7 +276,6 @@ public async Task AsyncJobMultipleTimesout() public async Task AsyncJobMultipleCompletesOnIncompleteResult() { SteamClient client = new SteamClient(); - client.jobManager.SetTimeoutsEnabled( true ); AsyncJobMultiple asyncJob = new AsyncJobMultiple( client, 123, call => call.IsFinished ); asyncJob.Timeout = TimeSpan.FromSeconds( 1 ); @@ -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" ); @@ -310,7 +308,6 @@ public async Task AsyncJobMultipleCompletesOnIncompleteResult() public async Task AsyncJobMultipleCompletesOnIncompleteResultAndFailure() { SteamClient client = new SteamClient(); - client.jobManager.SetTimeoutsEnabled( true ); AsyncJobMultiple asyncJob = new AsyncJobMultiple( client, 123, call => call.IsFinished ); asyncJob.Timeout = TimeSpan.FromSeconds( 1 );