KreonZZ
KreonZZ

Reputation: 333

How to properly use Fire&Forget in Async Environment

Consider the following:

//base stuff
private readonly ConcurrentQueue<message> queue = new ConcurrentQueue<message>();
private readonly MyCacheData _cache  = new MyCacheData ();
//setuo
timer = new Timer { Interval = 60_000, AutoReset = true };
timer.Elapsed += OnTimedEvent;
httpClient.Timeout = new TimeSpan(0, 0, 60); // 60 seconds too
//

// each 60 seconds
private async void OnTimedEvent(object sender, ElapsedEventArgs e)
{
   if (cache 30 minutes old)
   { 
      //Fire and Forget GetWebDataAsync()
      // and continue executing next stuff
      // if I await it will wait 60 seconds worst case
      // until going to the queue and by this time another 
      // timed even fires
   }

   // this always should execute each 60 seconds
   if (queue isnt empty)
   {
       process queue
   }
}

// heavy cache update each 10-30 minutes
private async Task GetWebDataAsync()
{
   if (Semaphore.WaitAsync(1000))
   {
      try
      {
            //fetch WebData update cache
            //populate Queue if needed
      }
      catch (Exception)
      {
      }
      finally
      {
          release Semaphore
      }
   }
}

Colored: https://ghostbin.com/paste/6edov

Because I cheat and use the cheap ConcurrentQueue solution I don't really care much about what happens during GetWebDataAsync(), I just want to fire it and do its job, while I instantly go to process queue because it always must be done each 60 seconds or timer resolution.

How do I correctly do that, avoid much overhead or unnecessary thread spawning?

EDIT: got an answer for my case elsewhere

private async void OnTimedEvent(object sender, ElapsedEventArgs e)
{
    async void DoGetWebData() => await GetWebDataAsync()

    if (condition)
    { 
        DoGetWebData(); // Fire&Forget and continue, exceptions handled inside
    }

        //no (a)waiting for the GetWebDataAsync(), we already here
    if (queue isnt empty)
    {
        //process queue
    }

}


private async Task GetWebDataAsync()
{
    if (Semaphore.WaitAsync(1000))
    {
        try
        {
        //fetch WebData update cache
        //populate Queue if needed
        }
        catch (Exception)
        {
            //log stuff
        }
        finally
        {
            ///always release lock
        }
    }
}

Upvotes: 1

Views: 258

Answers (2)

Jaster
Jaster

Reputation: 8581

Task.Run(...);
ThreadPool.QueueUserItem(...);

Anything wrong with these?...

How about something like that:

    ManualResetEvent mre = new ManualResetEvent(false);

    void Foo()
    {
        new Thread(() => 
        {
            while (mre.WaitOne())
            {
                /*process queue item*/
                if (/*queue is empty*/)
                {
                    mre.Reset();
                }
            }
        }) { IsBackground = true }.Start();
    }

    void AddItem()
    {
        /*queue add item*/
        mre.Set();
    }

Upvotes: 1

Vibeeshan Mahadeva
Vibeeshan Mahadeva

Reputation: 7238

Call an async method from another async method without await statement

Upvotes: 0

Related Questions