1

Following up with solutions provided in many questions around Fire and Forget. My scenario is that I want to run the Forgotten events in order they were triggered.

My solution is based on Simplest way to do a fire and forget method in c# 4.0

Here is my test code. And as expected it never guaranteed what order they will be processed.

    static void Main(string[] args)
    {
        Test(5);
        Console.WriteLine("5 sent");

        Test(2);
        Console.WriteLine("2 sent");

        Test(1);
        Console.WriteLine("1 sent");

        Test(4);
        Console.WriteLine("4 sent");

        Console.WriteLine("all sent");
        Console.ReadLine();

    }

    private static void Test(int messageNumber)
    {
        Action myMethod = () => {
            Task.Delay(messageNumber * 1000);
            Console.WriteLine(messageNumber);
        };
        Blindly.Run(myMethod);
    }

and my output

5 sent
2 sent
1 sent
4 sent
all sent
2
1
5
4

Imagine, you are using Fire and Forget for logging. So you don't want to block the calling code, but want to write all logged data in order they occurred.

Community
  • 1
  • 1
Yahya
  • 3,386
  • 3
  • 22
  • 40
  • 1
    Why not queue your actions and invoke them in the order you want? – Shocked Oct 11 '16 at 11:22
  • You do realize the `Task.Delay(messageNumber * 1000);` is useless in this scenario since it is not awaited? There will be no delay before the next line `Console.WriteLine(messageNumber);` – Peter Bons Oct 11 '16 at 17:23

2 Answers2

1

I'd use the ActionBlock of the TPL Dataflow (See http://blog.stephencleary.com/2012/09/introduction-to-dataflow-part-2.html for an intro)

It's a NuGet package, so see if it fits your framework version requirements.

static void Main(string[] args)
{
    var a = new ActionBlock<int>(async (messageNumber) => 
    {
        await Task.Delay(messageNumber * 1000);
        Console.WriteLine(messageNumber);
    });

    a.Post(5);
    Console.WriteLine("5 sent");

    a.Post(2);
    Console.WriteLine("2 sent");

    a.Post(1);
    Console.WriteLine("1 sent");

    a.Post(4);
    Console.WriteLine("4 sent");

    Console.WriteLine("all sent");
    Console.ReadLine();
}

It will be processed in a fire-and-forget manner in the order it has been posted to the ActionBlock.

Output:

5 sent
2 sent
1 sent
4 sent
all sent
5
2
1
4
Peter Bons
  • 26,826
  • 4
  • 50
  • 74
0

I'd do the following:

  • keep a timestamp for all your logged events
  • don't write the events to log immediately (since you're running it asynchronously, you're hopefully already not that worried about it); instead keep a queue (a collection, not necessarily FIFO) of logged messages
  • every X milliseconds, if you have queued log messages, sort and log all the ones that are older than Y milliseconds (X and Y will depend on your requirements/setup)
  • attempt to flush the log whenever the application exits (make sure you're doing it even if it's an exception)
decPL
  • 5,384
  • 1
  • 26
  • 36