How to map the custom object with corresponding Task in the following scenario?

Navjot Singh

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.

Mong Zhu

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.

edited at
0

Comments

0 comments
Login to comment

Related

How to use threading or Task pattern in following scenario

How to copy for the following scenario?

How to get result in following scenario

How to deal with following scenario in QTP?

How to map multiple Subject in an object literal to an object literal of corresponding Observable

How to avoid duplicates in following SQL scenario

How to make the checkbox working properly in following scenario?

How to show the groupwise result for the following scenario?

How would I improve the performance in the following scenario

How to use python metaclass for the following scenario?

How to improve typescript's performance in the following scenario

How to apply conditional aggregation in SQL the following scenario?

how to make a left outer join in following scenario

Will setstate run after Object map in this scenario?

Way(Optimized) to Implement following Scenario : Split Object in a List<T>

How to map JSON fields to custom object properties?

How to add custom property of object using .map

How to call a jQuery function on click event in the following scenario?

How to remove \' from each array element in following scenario?

How to access json data and use in if condition in following scenario?

How can I schedule local notification for the following scenario?

How to do something like unpivot like in oracle sql for the following scenario?

How to append data to a particular div in jQuery in the following scenario?

How to access outer div element in jQuery following scenario?

How to show/hide the content of a table in following scenario using jQuery?

How can I use list comprehension in following scenario?

How to identify object according to the given scenario

How to convert the following map/list?

How do I solve this multitasking scenario with respect to long task interruption?