In the following code, the cancellation source token is passed to Task.WhenAll.
// This is part of the InitializerProcess.Init method
try
{
InitializationResult[] rs = await Task.Run(() => Task.WhenAll(tasks), m_source.Token);
}
catch (OperationCanceledException e)
{
Debug.Log($"{nameof(OperationCanceledException)} thrown with message: {e.Message}");
return null;
}
finally
{
m_source?.Dispose();
}
Using Unity Unit test framework with the following where the tasks are simply two classes waiting for 0.5s:
[UnityTest]
public IEnumerator InitializerTestCancelPasses()
{
var init = new InitializerProces();
Task<List<InitializationResult>> asyncOperation = init.Init(m_initializer);
while (!asyncOperation.IsCompleted)
{
init.Cancel();
yield return null;
}
Assert.IsNull(asyncOperation.Result);
}
The weird situation is that the first run does not pass, then following runs pass. I'm suspicious the following runs are actually cancelling some leftover tasks from previous run and is not working as expected.
There could be something wrong with the Unity Unit test framework as async is not yet fully supported (as of 10/04/2024, only in a pre-release package that I am not using) and requires a workaround with coroutines, but maybe I'm not using the token and tasks properly.
the cancellation source token is passed to Task.WhenAll.
No, it is passed to Task.Run
, so if the token is already cancelled, Task.WhenAll(..)
will never run. If the token is not already cancelled it will likely have no effect. It also seem weird to use Task.Run
in this way instead of just awaiting Task.WhenAll
.
Task.WhenAll do not have any overload that takes a cancellation token, so if you want proper cancellation you probably need to ensure the token is passed to each task, and that the token is actually used correctly by each task.
The weird situation is that the first run does not pass, then following runs pass. I'm suspicious the following runs are actually cancelling some leftover tasks from previous run and is not working as expected.
A possible reason is that some objects are not recreated between tests. If you have multiple tests it can be fairly easy to unintentionally create dependencies between test. But I'm not familiar with unitys testing framework, so I can't really suggest fixes.