0

How to keep a console application open even if all the awaitables finished, but without interrupting other possible awaitables?

I know my question sounds strange but just to explain:

I'm using the Telegram.Bot library and I need to listen to all the incoming updates from telegram. The problem is that as soon as I set the Update Handler the console just closes.

Another thing I have is a request using RestSharp that gets a json from API every x minutes, that does the job done keeping the console alive because I'm using a way to detect console cancelation before interrupting the loop.

Is there another better way of doing what I want?

This is what I'm using for console close listening https://stackoverflow.com/a/22996661/12420972

And I have the exitSystem as a variable for a while loop

while (!exitSystem)
     // Do this
Uwe Keim
  • 39,551
  • 56
  • 175
  • 291

1 Answers1

3

Using while loop will unnecessary waste the CPU cycles, because all you want to do is wait for exit signal. You can wait for a task completion event asynchronously using the the TaskCompletionSource. Below is the code which gives you an idea how to implement it.

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp
{
    public class Program
    {
        private static readonly TaskCompletionSource<object> TaskCompletionSrc = new TaskCompletionSource<object>();
        static async Task<int> Main(string[] args)
        {
            Console.WriteLine("Launching background tasks...");
            var thread = new Thread(DoSomethingInBackground);
            thread.Start();

            //wait for the task completion event
            await TaskCompletionSrc.Task;

            Console.WriteLine("Task completed. Exiting...");
            return 0;
        }

        private static void DoSomethingInBackground()
        {
            Thread.Sleep(5000);
            //signal that task has completed
            TaskCompletionSrc.SetResult(null);
        }
    }
}

Updated Answer:

using System;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp
{
    public class Program
    {
        //API call interval in milliseconds
        private const int ApiCallIntervalMilliSeconds = 5000;
        public static void Main(string[] args)
        {

            //create token source for cancelling the background operations when the main thread exists
            using (var cancellationTokenSrc = new CancellationTokenSource())
            //create timer which triggers the MakeApiCallback immediately and repeats for every specified milliseconds
            using (var timer = new Timer(TriggerApiCall, cancellationTokenSrc, TimeSpan.Zero,
                TimeSpan.FromMilliseconds(ApiCallIntervalMilliSeconds)))
            {
                Console.WriteLine("Program is running. Press any to exit...");

                //blocks the main thread from running to completion
                Console.Read();

                //key press, cancel any API calls in progress
                cancellationTokenSrc.Cancel();
            }

        }

        public static async void TriggerApiCall(object argument)
        {
            var tokenSrc = (CancellationTokenSource) argument;
            await MakeApiCall(tokenSrc.Token);
        }


        private static async Task MakeApiCall(CancellationToken cancellationToken)
        {
            Console.WriteLine("API Call in progress...");
            try
            {
                //simulate the background work
                await Task.Delay(3000, cancellationToken);
            }
            catch (TaskCanceledException)
            {
                Console.WriteLine("API call cancelled!");
                return;
            }
            catch(Exception ex)
            {
                Console.WriteLine("API call failed. Exception:" + ex);
                return;
            }

            Console.WriteLine("API call completed successfully.");
        }
    }
}
zafar
  • 1,965
  • 1
  • 15
  • 14
  • Sorry but it doesn't help answering my question. I need to keep the console alive until I close the terminal not to wait for something to complete. As I said I use the while loop to gather data from a json API every x seconds so I still need the loop. I just don't want it to block anything after I call my method containing the loop – nitanmarcel Apr 28 '20 at 16:31
  • Here's something I tried with your answer https://del.dog/jecurrekyg.cs – nitanmarcel Apr 28 '20 at 16:34
  • If you want to make the API call every x seconds, use timer, you don't need while loop – zafar Apr 28 '20 at 16:36
  • I'm used to python where combining threading with asyncio is a living hell – nitanmarcel Apr 28 '20 at 16:39
  • @nitanmarcel yes, let me post an example – zafar Apr 28 '20 at 16:57
  • Thanks :) I'm happily waiting for an example :) – nitanmarcel Apr 28 '20 at 17:19