Home > OS >  Async await with timer
Async await with timer

Time:08-06

I am trying to use the Timer to trigger an event to send data across the network.Basically I have a List I'd like to send. I want the following to happen:

  1. Add item to List (async) Start Timer for 10 seconds

  2. Wait for 10 seconds until there another call to add item to list.

  3. Add second string to List if there is another call and reset timer. Or Else Elapse

  4. Save all at once after elapse

So I have this:

public class Foo
{
public static List<string> list;
public static Timer timer;
static Foo()
{
    list = new List<string>();
    timer = new Timer(10000);
    timer.Enabled = true;
    timer.AutoReset = false;
    timer.Elapsed  = SendToServer;
}

public static async void Log(string value)
{
    list.Add(value);
    timer.Stop();
    timer.Start();
    await Task.Delay(10000);
}

static void SendToServer(object sender, ElapsedEventArgs e)
{
    //TODO send data to server

    //AutoReset is false, so neither of these are needed
    //timer.Enabled = false;
    //timer.Stop();
}
}

This works as expected, however the caller is like

  1. Foo.log("a");
  2. Foo.log("b");
  3. Foo.Commit(); ---> this method should check if all the Data sent are saved. If not Save the remaining.

The issue here is Elapsed event ( SaveToServer) will trigger after Commit.

Let me know for any resolution or to take another approach.

CodePudding user response:

async void is in almost all situations a bad idea.

With your current logic if Log is called, let's say, every 5 seconds you will never send the data to the server. This may or may not be what you want.

If you want to send in batches every now and the (for example sending logs) I suggest that you separate sending and adding to the list:

  1. Log just adds to the list - this doesn't need to be async
  2. Send just sends the content of the list (and clears it in a thread safe way) and is called by some background worker service.

If you want to send 10 after last input you could try something like this:

// TODO make thread-safe if needed
public class C
{
   private static List<string> list = new();
   private static CancellationTokenSource cts = new ();

   public static void Log(string value)
   {
     list.Add(value);
     cts.Cancel();
     SendToServer();
   }

   static async Task SendToServer()
   {
     try
     {
        await Task.Delay(TimeSpan.FromSeconds(10), cts.Token);
     } 
     catch(TaskCanceledException)
     {
        return;
     }
     // Make a copy, clear `list` send copy to server
   }
}
  • Related