Using Task ContinueWith to delay execution of code - c#

I need to add delay to some code block. I am using Task ContinueWith to achieve that, it works as expected when tested on my machine but the deployed code is not working.
public void DailyReminder()
{
//Do somethings
System.Threading.Tasks.Task.Delay(300000).ContinueWith(t => EmailAlert()); //This should not block UI
//Do more things, this should not wait for 300000 ms to get excecuted
}
public void EmailAlert()
{
//Send Email
}
For Example i need the below code to produce A B C and D only after the 5 sec delay -
using System;
using System.Threading.Tasks;
namespace HelloWorld
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("A");
EmailAlert();
Console.WriteLine("C");
}
private static async Task EmailAlert()
{
Console.WriteLine("B");
await Task.Delay(5000);
Console.WriteLine("D");
}
}
}

You should separate your EmailAlert (which is a fire-and-forget task) and the logic that is not dependent on the task.
public void DailyReminder()
{
// A discard pattern to make it explicit this is a fire-and-forget
_ = EmailAlert();
// Additional code that does not depend on the preceding task
}
public async Task EmailAlert()
{
await Task.Delay(300_000);
// await Some email sending logic
}

it works as expected when tested on my machine but the deployed code is not working.
If you're using some kind of shared or cloud hosting, it's normal to have your app shut down when it's done servicing requests for some time. This is why fire-and-forget on ASP.NET is dangerous.
Since you definitely want your email to be sent, fire-and-forget is not an appropriate solution. Instead, you want a basic distributed architecture:
Instead of sending the email from ASP.NET, serialize it to a message sent to a durable queue.
Have a separate background process read that queue and send the actual email.

I'm not sure of where in your code you are trying to create this delay, but you normally don't have the control over how long a thread will be alive when deploying your application to a server.
Normally a thread is created when a user sends a request to the application, and when it returns its response the thread will be stopped.
Also, the web server may close down the entire application when there's no traffic for a while.
The solution for these long running methods is to use Worker services.
You can read more from the documentation at https://learn.microsoft.com/en-us/dotnet/core/extensions/workers

You try use case this :
public void DailyReminder()
{
//Do somethings
System.Threading.Tasks.Task.Delay(300000).ContinueWith(t => EmailAlert()).Wait(); //This should not block UI
//Do more things, this should not wait for 300000 ms to get excecuted
}
public void EmailAlert()
{
//Send Email
}

Related

Looping infinitely using threads in Windows Service

I've seen several posts on SO that are similar to my question, but none of them have solved my problem. I'm creating a windows service that is going to poll a Redis database every few seconds or so and perform an action based off of the result. I'd like to create a "thread pool" of sorts so that I can run multiple actions at the same time if I get a result from Redis while another command is being processed (on another thread).
One of my main problems is that when I stop my Windows service, the process still stays alive for ~30 seconds or so instead of closing down. Here are the relevant code snippets:
Thread Worker;
IDatabase db = ...;
AutoResetEvent StopRequest = new AutoResetEvent(false);
protected override void OnStart(string[] args) {
var poller = new Poller();
Worker = new Thread(() => poller.Poll(StopRequest));
Worker.Start();
}
protected override void OnStop() {
// Signal worker to stop and wait until it does
StopRequest.Set();
Worker.Join();
}
Here's an example of the Poller classes Poll method.
public async void Poll(AutoResetEvent finished)
{
var res = string.Empty;
while (!finished.WaitOne(1000))
{
res = db.StringGet($"task");
if (!String.IsNullOrEmpty(res))
{
ParseAction(res);
}
db.KeyDelete($"task");
}
}
So this code (with a lot trimmed out) stays running in the background correctly, and seems to process incoming queries from Redis just fine, but I'm having the issue with the process not closing correctly as I mentioned above. I'm also not sure if this is the best approach to take for this situation. I'd love some pointers on better or more "idiomatic" ways to handle this threading issue.
Thanks!
A better way to deal with Windows service is to move entire processing into a background task. That will allow you to handle startup and shutdown much more gracefully.
And if you use Task to simulate polling, then you can use CancellationToken to propagate shutdown event to other layers of processing. Here you can find how to simulate timer using Task. Please read
Is there a Task based replacement for System.Threading.Timer?
Here is the code sample of windows service OnStart and OnStop handlers with background task that starts and shuts down quickly. This code is based on .NET 4.6.1.
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
using System.ServiceProcess;
namespace TEST.MY.SERVICE
{
partial class MyService : ServiceBase
{
private Task _initializationTask;
private CancellationTokenSource _initializationCancelTokenSource;
private CancellationToken _intitializationCancellationToken;
public MyService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
_initializationCancelTokenSource = new CancellationTokenSource();
_intitializationCancellationToken = _initializationCancelTokenSource.Token;
_initializationTask = Task.Run(() =>
{
//Kick off polling from here that also uses _intitializationCancellationToken, so that when _initializationCancelTokenSource.Cancel() is invoked from OnStop it will start cancellation chain reaction to stop all running activity. You can pass it even into your methods and check _intitializationCancellationToken.IsCancellationRequested and take appropriate actions.
//using the Task timer from the other stack overflow post, You could do something like
Task perdiodicTask = PeriodicTaskFactory.Start(() =>
{
Console.WriteLine(DateTime.Now);
//execute your logic here that has to run periodically
}, intervalInMilliseconds: 5000, // fire every 5 seconds...
cancelToken: _intitializationCancellationToken); // Using same cancellation token to manage timer cancellation
perdiodicTask.ContinueWith(_ =>
{
Console.WriteLine("Finished!");
}).Wait();
}, _intitializationCancellationToken)
.ContinueWith(t =>
{
//deal with any task related errors
},TaskContinuationOptions.OnlyOnFaulted);
}
protected override void OnStop()
{
try
{
_initializationCancelTokenSource?.Cancel();
_initializationCancelTokenSource?.Dispose();
_initializationTask?.Dispose();
}
catch (Exception stopException)
{
//log any errors
}
}
}
}
Here you can find more details about how to cancel a waiting task. https://msdn.microsoft.com/en-us/library/dd321315(v=vs.110).aspx
This should give you a good idea on how to design your windows service. Make necessary tweeks for your needs. Get yourself familiarize with c# Task library.
have you pondered using a Boolean/Binary flag to find out if the service is in fact running? or perhaps performing a Call within the start of the Loop to check? I'm not familiar enough with C# in order to fully comprehend the entire task at hand, but I know that when Multi-Threading is involved, Binary/Boolean Flags are on average rather Stable.
For Example, I play a Steam Game that is in Beta (Space Engineers) that uses C# and it seems to consistently have problems with Multi-Threading errors and clearing Parent Data after every execution, but the Mod Authors on Steam Workshop have a Tendency of using Boolean and Binary Flags in order to ensure their tasks don't get stuck or crash because the Load Times to relaunch the Game are horrific, so they attempt to avoid as many crashes as possible.
It might not be Fancy, but as long as you ensure it doesn't create a runaway Memory Leak, you should be fine. I recommend, if using an Incremental Variable for your Unique Identifier for each Task, to Explicitly set an Upper Limit somewhere, and when said limit is reached, it will call that Task and reset the Incremental Variable to Zero (with lots of Buffer Space to prevent Accidental Data Loss).
If the Task is running, it will perform the call, set the Boolean, and execute, might desire another call to verify the task is still running before attempting to write to the destination, as I am assuming that without the Task, the Information does nothing, and if the Task isn't running, it will delve into the if != isRunning and get sent to the correct destination to kill the Thread.
I hope this information is helpful to you, as I mentioned before, I'm only a beginner in C#, so I'm not as familiar with the Advanced Commands as some of the other Users on here.

windows service recursive infinite loop with delayed execution for synchronous task

I am building a Windows Service to read records from a table, pass record data to a WCF Service, wait for its response and update the same record in the database depending on the response from the WCF Service. This process will continue for all the records and once all the records are processed, I need to delay further execution of code for n number of minutes. After the n minutes has elapsed, I need to call the same code to read records from the table again and process them and once all the records are processed, delay execution again for n number of minutes. This need to happen infinitely and the most important point is that all the executions should happen synchronously including the delayed execution, I want to completely avoid using Threading or async/await or any other asynchronous programming techniques.
After searching for while, I have learned that with .NET Framework 4.5, the recommended way is using Task.Delay() method without using asycn/await keywords to add a delay synchronously. So I have created a simple console application having a recursive method with an infinite loop:
class Program
{
static void Main(string[] args)
{
RecursiveMethod();
}
public static void RecursiveMethod()
{
while (true)
{
DoWork();
Console.WriteLine("Task delayed...");
Task.Delay(3000).Wait();
Console.WriteLine("Calling method again recursively...");
RecursiveMethod();
}
}
public static void DoWork()
{
//Do some work
Console.WriteLine("Work Completed.");
}
}
The above code seems to be working fine but I faced big issues when implementing System.Timers.Timer in another windows service, after running properly for two days, the Timer completely stopped working without throwing any exception, so no error was logged which is very frustrating.
I want to avoid such situations, so what is best way to implement Task.Delay() for simple synchronous code? The delay will be set to 2 hours so I want to also handle situations where the Task.Delay() will get garbage collected or removed from memory or stops working on its own (without throwing any exception) and restart the whole process again.
Just use Thread.Sleep(3000). Not sure why you want to avoid that. Your code is sync, so you shouldn't be using Task.
Also, Task.Delay uses a Timer. So not sure if that's going to solve your problem.
I'd try and figure out why the Timer object stopped working. That doesn't sound right.
Was your timer callback wrapped with a try catch?
As others have noted, Task.Delay is not appropriate here, since your code is not asynchronous. Also, you already have an infinite loop (while (true)), so there is no need for recursion:
class Program
{
static void Main(string[] args)
{
while (true)
{
DoWork();
Console.WriteLine("Task delayed...");
Task.Sleep(3000);
}
}
public static void DoWork()
{
//Do some work
Console.WriteLine("Work Completed.");
}
}

Asynchronous programming with .NET Core?

I am newbie to .NET Core and asynchronous programming. I am trying to implement a console application to do the following:
The console application should work as intermediator between two external APIs. eg. API-1 and API-2.
It should call API-1 after every 10 milliseconds to get data.
Immediately call API-2 to submit the data that is received from API-1.
Console Application needs to wait for API-1 to receive data, but does not have to wait for the response from API-2.
Below is my code. It not working as expected. At first it invokes API-1 in 10 milliseconds as expected, but after that its invoking API-1 ONLY AFTER it receives response from API-2.
So assume API-2 takes 20 seconds, API-1 is also getting invoked after 20 seconds.
How do I make API-2 call asynchronous so it does not have to wait for API-2 response?
namespace ConsoleApp1
{
public class Program
{
private static Timer _timer;
private const int TIME_INTERVAL_IN_MILLISECONDS = 10; // 10 milliseconds
private const int API2_DELAY = 20000; // 20 seconds
public static void Main(string[] args)
{
Dowork().Wait();
Console.WriteLine("Press Any Key to stop");
Console.ReadKey();
Console.WriteLine("Done");
}
private static async Task Dowork()
{
var data = new SomeData();
_timer = new Timer(CallAPI1, data, TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite);
await Task.Yield();
}
private static async void CallAPI1(object state)
{
var data = state as SomeData;
Console.WriteLine("Calling API One to get some data.");
data.SomeStringValue = DateTime.Now.ToString();
await CallAPI2(data);
_timer.Change(TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite);
}
private static async Task CallAPI2(SomeData data)
{
Console.WriteLine("Calling API Two by passing some data received from API One " + data.SomeStringValue);
// the delay represent long running call to API 2
await Task.Delay(API2_DELAY);
}
}
}
POCO class
namespace ConsoleApp1
{
public class SomeData
{
public string SomeStringValue { get; set; }
}
}
Also note that API-1 and API-2 will be developed in ASP.NET Core 1
Update1
Let me rephrase above sentence. The API-1 would be developed in .Net core but API-2 would be windows workflow service. That means we can make multiple calls to WF. The WF will persist the requests and process one at a time.
Update2
After going through all the answers and links provided. I am thinking to use windows service as intermediator instead of console application. Right now .Net core does not support window service but has this nuget-package that can host .Net core inside windows service or I might use classic windows service using 4.6.2. I guess I can do the asyncrous implementation inside windows service as well.
There are a lot of things that I would do differently in this situation. Rather than using a timer I would use Task.Delay, also - I would most certainly wait for API2 to complete before attempting to throw more data at it. Additionally, I would ensure that my async methods are Task or Task<T> returning, notice your CallAPI1 call isn't, I understand it's a timer callback -- but that is another issue.
Consider the following:
async Task IntermediateAsync()
{
Console.WriteLine("Press ESC to exit...");
while (Console.ReadKey(true).Key != ConsoleKey.Escape)
{
var result = await _apiServiceOne.GetAsync();
await _apiServiceTwo.PostAsync(result);
// Wait ten milliseconds after each successful mediation phase
await Task.Delay(10);
}
}
This will act in the following manner:
Print a line instructing the user how to exit
Start loop
Get the result of API1
Pass the result to API2
Wait 10 milliseconds
[Step 2]
Finally, this is the same suggestion regardless of whether or not your using .NET Core. Any API interactions should follow the same guidelines.
Notes
Using a fire-and-forget on the second API call is simply setting your code up for failure. Since it is an API call there is more than likely going to be some latency with the I/O bound operations and one should assume that a tight loop of 10 milliseconds is only going to flood the availability on that endpoint. Why not simply wait for it to finish, what reason could you possibly have?
Remove the await when calling API2
private static async void CallAPI1(object state)
{
var data = state as SomeData;
Console.WriteLine("Calling API One to get some data.");
data.SomeStringValue = DateTime.Now.ToString();
//Before this will cause the program to wait
await CallAPI2(data);
// Now it will call and forget
CallAPI2(data);
_timer.Change(TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite);
}
Edit:
As David points out, of course there is many way to solve this problem. This is not a correct approach to solve your problem.
Another method of doing things is use quartz.net
Schedule API1 as a repeating job
When API1 is done, schedule another job to run API2 as a standalone job
This way when API2 fails you can replay/repeat the job.

How to run WCF web service and multithread task inside windows service separately?

I have windows service and WCF web service hosted inside. Infinite task needs to read some logs from device every 2 seconds. In same time web service methods should work properly when they are called. In my case, when i Debug it seems that web service methods calls interrupts Infinite task. So my task is not running on different thread.
How can I optimize my code to work separately from WCF web service? Where is the problem?
On windows service start
protected override void OnStart(string[] args){
//....other code for starting WCF web service....
work();
}
work method:
public async void Work() {
log.Debug("operation started");
Methods checkE = new Methods();
try
{
await checkE.PullLogs();
}
catch (Exception ex) {
log.Error(ex.Message);
}
}
This is PullLogs method:
public async Task PullLogs ()
{
while (true)
{
... some code ...
Parallel.ForEach(tasks, task =>
{
byte[] dataArrayPC;
byte[] dataArrayCT;
byte[] rezult;
PTest p = new PTest();
if (p.PingIt(task.Ip))
{
try
{
SDKCommunication con = new SDKCommunication(task.Id, task.Ip, port, timeout, false);
...some code...
while (indexPC <= indexCT )
{
int broj = con.ReadLogs(address, LOGS, indexPC, 16, 0);
rezult = con.GetLogs(broj);
readEventData(rezult);
indexPC = indexPC + 16;
if (maxiterrations > itteration) {
//send to Java web service
}
itteration++;
}
con.Dispose();
else { log.Debug("error in sdk"); con.Dispose(); }
}
catch (Exception e) { log.Debug(e.Message); }
}
else { log.Error("no connection to device: " + task.Ip); }
}
);
await Task.Delay(2000);
}
}
EDIT:
One more question, is it better to use while(true) and Task.Delay(2000) or have timer tick for every 2 seconds?
Thanks
I'm not sure you are seeing what you think you are seeing. It sounds like you observed with the debugger that WCF service call interrupted your PullLogs code ... but perhaps the code was executing concurrently on different threads, and the debugger just switched you from one to another when a breakpoint was hit or something similar.
In general your WCF service method calls should be executing on the IO Completion Thread Pool. Your TPL code in the Parallel.ForEach should be executing with the default TaskScheduler on the default Thread Pool.
See here for more on specifying your own sychronization context (which will determine which threads WCF code can execute on):
Synchronization Contexts in WCF
If your goal is to make sure that no WCF service calls are processed while your PullLogs code is running, then you will need a synchronization approach, like locking on the same object from the WCF methods, and also from the PullLogs code.
If instead your goal is to make sure that these two parts of your code are isolated, so that both are available to run simultaneously, then I don't think you need to do anything.
Now if you have observed that while your PullLogs code is executing, the WCF service is not as available as you want it to be, then I would take this to indicate that some resource (hardware threads, who knows) is being oversubscribed by the parallel loop in your PullLogs method. In that case probably the best you would be able to do is to naively limit concurrency in that loop to some smaller value ... which might slow down your PullLogs method, but could also go a long way towards making sure your WCF service remains available.
If you want to give this a try, you can create a LimitedConcurrencyTaskScheduler as is done here:
How to: Create a Task Scheduler That Limits Concurrency
and then in your code, supply an instance of this task scheduler to your call to Parallel.ForEach.
Again I don't think this should be necessary unless you have noticed an actual problem (so far you only indicate that you noticed some behavior in the debugger that you didn't expect, but that sounds perfectly reasonable to me).

trigger other parts of code to continue (C#)

I am modifying an old, large (and un-documented) program in C# that uses an API to talk on a serial bus.
Is there some way of letting OnIndication trigger SendRepeatRequest to continue?
I would like to avoid polling a flag with wait Xms as response time varies greatly and I need quick responses.
//Pseudocode
public void SendRepeatRequest(int X)
{
SendToAPI();
// Wait until API responds, usually a few ms but can take 1-2min
// loop X times
}
//this is activated by the API response
public void OnIndication()
{
// Handle request from API...
// Tell SendRepeatRequest to continue
}
Do you have any suggestions on how to do this?
Thanks!
You may want to look into the Task library (introduced in .NET 4.0 under the System.Threading.Tasks namespace). It has a variety of threading operations to do this pretty easily.
I believe the following section might help (or get you started).
public void OnIndication()
{
Task doWork = new Task(() =>
{
// Handle request
});
Action<Task> onComplete = (task) =>
{
SendRepeatRequest(X, args)
};
doWork.Start();
doWork.ContinueWith(onComplete, TaskScheduler.FromCurrentSynchronizationContext());
}

Categories

Resources