I am developing a console application in which I have a third party rest client (wordpress rest client to be precise), which has some methods with return Task
objects. An example method signature can be like:
public Task<bool> Delete(int id);
I have a list of Post
to be deleted. I could do something simply like:
public void DeleteGivenPosts(List<Post> posts) {
posts.ForEach(async post => await wpRestClient.Delete(post.Id));
}
In this case the deletion is fire and forget. It would be better if I log the information about the post which is deleted. A log statement like:
logger.Log($"A post with {post.Id} is deleted");
So, I decided to project the Tasks.
public async Task DeleteGivenPosts(List<Post> posts) {
var postDeletionTasks = posts.Select(post => wpRestClient.Delete(post.Id));
foreach (var deletionTask in TaskExtensionUtil.GetTasksInCompletingOrder(postsDeletionTasks)) {
bool deletionResult = await deletionTask;
if(deletionResult) {
//i want to log success of deletion here
} else {
//i want to log the failure of deletion here
}
}
}
Here TaskExtensionUtil.GetTasksInCompletingOrder()
is a helper method which returns the tasks in the order they complete. Code for this is:
public static List<Task<T>> GetTasksInCompletingOrder<T>(IEnumerable<Task<T>> sourceTasks) {
var sourceTasksArr = sourceTasks.ToArray();
var taskCompletionSourceArr = new TaskCompletionSource<T>[sourceTasksArr.Length];
var currentSlot = -1;
for (int i = 0; i < sourceTasksArr.Length; i++) {
taskCompletionSourceArr[i] = new TaskCompletionSource<T>();
sourceTasksArr[i].ContinueWith(prev => {
int indexToSet = Interlocked.Increment(ref currentSlot);
taskCompletionSourceArr[indexToSet].SetResult(prev.Result);
});
}
return taskCompletionSourceArr.Select(i => i.Task).ToList();
}
The problem is that the deletionResult
is a bool
. In order to log information about which post is deleted I need to get the Post
object associated with the deletion task.
I was thinking to create a dictionary that maps the deletion task to the corresponding Post
by doing something like:
posts.Select(post => new { deletionTask = wpRestClient.Delete(post.Id), post})
.ToDictionary(i => i.deletionTask, i => i.post);
But this will not work because in the GetTasksInCompletingOrder
the original deletion tasks are translated to TaskCompletionSource
tasks. So I will always get an exception that the key is not present in the dictionary. Also I am not sure how will a dictionary behave when it has Task
objects as keys.
At this point I have no clue how to achieve the logging. I will appreciate any help.
how about to write the logstatement after deletion?
public async Task DeleteGivenPosts(List<Post> posts)
{
await Task.WhenAll(
posts.Select(async post =>
{
bool res = await wpRestClient.Delete(post.Id);
string message = res ? $"Post {post.Id} is deleted" : $"Post {post.Id} survived!";
logger.Log(message);
}));
}
Here is a small LinqPad Programm to examplify the workings of the method:
async void Main()
{
List<Post> postList = Enumerable.Range(1, 12).Select(id => new Post {Id = id}).ToList();
Console.WriteLine("Start Deletion");
await DeleteGivenPosts(postList);
Console.WriteLine("Finished Deletion");
}
public static MyRestClient wpRestClient = new MyRestClient();
// Define other methods and classes here
public async Task DeleteGivenPosts(List<Post> posts)
{
await Task.WhenAll(
posts.Select(async post =>
{
bool res = await wpRestClient.Delete(post.Id);
string message = res ? $"Post {post.Id} is deleted" : $"Post {post.Id} survived!";
Console.WriteLine(message);
}));
}
public static Random rand = new Random(DateTime.Now.Millisecond);
public class MyRestClient
{
public async Task<bool> Delete(int i)
{
return await Task<bool>.Run(() => { Thread.Sleep(400); return rand.Next(1,4) == 1;});
}
}
public class Post
{
public int Id { get; set; }
}
Output:
Start Deletion
Post 1 is deleted
Post 3 survived!
Post 5 survived!
Post 6 survived!
Post 2 survived!
Post 4 survived!
Post 8 survived!
Post 7 survived!
Post 9 survived!
Post 11 survived!
Post 10 is deleted
Post 12 is deleted
Finished Deletion
Collected from the Internet
Please contact [email protected] to delete if infringement.
Comments