3

I'm going to use a Windows Service to send Telegram Messages periodically (Every two minutes). My Windows Service starts fine and after 2 minutes it is stopped. I checked my code and find out it is because of async. How can I solve the problem?

protected override void OnStart(string[] args)
{
    //< I declared a System.Timers.Timer to send new Telegram messages.
    aTimer = new System.Timers.Timer(120000); // 2 minutes
    aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
    aTimer.Enabled = true;

    GC.KeepAlive(aTimer);
    //>
}

private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
    SendNewMessages();
}

async static void SendNewMessages()
{
    MyDataContext myDB = new MyDataContext();
    var newMessages = myDB.TelegramMessages.Where(tm => tm.Status != "New Message");

    foreach (TelegramMessage newMessage in newMessages)
    {
        try
        {
            var store = new FileSessionStore();
            var client = new TelegramClient(store, "MySession");
            await client.Connect();

            var res = await client.ImportContactByPhoneNumber(newMessage.ReceiverPhoneNumber);
            await client.SendMessage(res.Value, newMessage.Message);

            newMessage.Status = "Sent";
            myDB.SubmitChanges();
        }
        catch (Exception ex)
        {
            newMessage.Status = ex.Message;
            myDB.SubmitChanges();
        }

        Thread.Sleep(5000);
    }
}
Mohsen
  • 971
  • 2
  • 11
  • 29
  • ` I checked my code and find out it is because of async` I doubt it. I recommend reducing this to a minimal reproducible example, and I suspect you'll find the actual problem is something else. E.g., an unhandled exception. – Stephen Cleary Apr 16 '16 at 13:20

1 Answers1

3

One thing I see directly is that async/await has not been implemented all the way to the eventhandler since "SendNewMessages" returns void. And your eventhandler is not async.

According to MSDN on "Async Return Types (C# and Visual Basic)"

The primary use of the void return type (Sub procedures in Visual Basic) is in event handlers, where a void return type is required. A void return also can be used to override void-returning methods or for methods that perform activities that can be categorized as "fire and forget."

This is most likely an issue in your scenario, so you could try changing your SendNewMessage to this

async static Task SendNewMessages()

And your eventhandler to this

private async static void OnTimedEvent(object source, ElapsedEventArgs e)
{
    await SendNewMessages();
}

UPDATED

It would also be a good idea to add some errorhandling code to your "SendNewMessages"-method since if an exception is thrown, your service will quit.

async static Task SendNewMessages()
{
    try
    {
    ... Your code here
    }
    catch(Exception e)
    {
    ... exceptionhandling here
    }
}

At the moment you only have exceptionhandling within your foreach, but you do not have any errorhandling (as far as I can see) for your database-code.

if an exception is throw here

MyDataContext myDB = new MyDataContext();
var newMessages = myDB.TelegramMessages.Where(tm => tm.Status != "New Message");

foreach (TelegramMessage newMessage in newMessages)

or here:

newMessage.Status = ex.Message;
myDB.SubmitChanges();

The service would end

Shazi
  • 1,490
  • 1
  • 10
  • 22