Credit to the author from this site:
https://codinginfinite.com/creating-scheduler-task-seconds-minutes-hours-days/
I can define the task execution parameter in 24hr time to run my method, but I see no logic in the code that is clear to me as to why it fires my method by a large multiplicity of times. The issue is that where my method should be executed only but once per minute starting at the specified time, it is actually executed 20+ times in less than one minute. I've tried altering parameters and repeat intervals, but nothing seems to resolve the issue and different execution intervals always fire the method many times over than what is specified - i.e. similarly, 5min interval, but I get 30+ order placements within one minute whereas I would expect not more than one order execution every 5 minutes..
Any ideas on why this could be happening with this code?
Here is the service class:
public class SchedulerService
{
private static SchedulerService _instance;
private List<Timer> timers = new List<Timer>();
private SchedulerService() { }
public static SchedulerService Instance => _instance ?? (_instance = new SchedulerService());
public void ScheduleTask(int hour, int min, double intervalInHour, Action task)
{
DateTime now = DateTime.Now;
DateTime firstRun = new DateTime(now.Year, now.Month, now.Day, hour, min, 0, 0);
if (now > firstRun)
{
firstRun = firstRun.AddDays(1);
}
TimeSpan timeToGo = firstRun - now;
if (timeToGo <= TimeSpan.Zero)
{
timeToGo = TimeSpan.Zero;
}
var timer = new Timer(x =>
{
task.Invoke();
}, null, timeToGo, TimeSpan.FromHours(intervalInHour));
timers.Add(timer);
}
}
Here is the scheduler class:
public class Scheduler
{
public static void IntervalInSeconds(int hour, int sec, double interval, Action task)
{
interval = interval / 3600;
SchedulerService.Instance.ScheduleTask(hour, sec, interval, task);
}
public static void IntervalInMinutes(int hour, int min, double interval, Action task)
{
interval = interval / 60;
SchedulerService.Instance.ScheduleTask(hour, min, interval, task);
}
public static void IntervalInHours(int hour, int min, double interval, Action task)
{
SchedulerService.Instance.ScheduleTask(hour, min, interval, task);
}
public static void IntervalInDays(int hour, int min, double interval, Action task)
{
interval = interval * 24;
SchedulerService.Instance.ScheduleTask(hour, min, interval, task);
}
}
Instantiated on page load with defined start time parameters and repeat interval:
protected void Page_Load(object sender, EventArgs e)
{
Scheduler.IntervalInMinutes(20, 15, 1,
() => {
buyOrder();
});
}
At 20:15, call this method and repeat every minute:
private static void buyOrder()
{
//This is only a basic POST method
}
Result:
I get the multiplicity of orders executed in <1min as mentioned.
The issue appears not to be in the code but rather the fact that you are running the scheduling instruction in the Page_Load event.
My educated guess is if you debug this, you will find that your Page_Load event is firing multiple times which causes multiple jobs to be scheduled.
There are a number of reasons why this could happen (like multiple event handlers, Ajax requests, or even the act of debugging through the code itself as some browsers will reissue requests if they don't receive a timely response) but the bottom line is you should rethink how/where you trigger the scheduling.
Related
I have a Xamarin.Forms project which uses a local database file Sqlite (the file is called datas.lite) from sqlite-net-pcl nuget package (version 1.2.0).
I have a table called Item:
public class Item
{
[PrimaryKey]
public int ID { get; set; }
public bool IsActive { get; set; }
}
And a repository ItemRepository with a static connection SQLite, I use to update the Item rows:
public class ItemRepository
{
private static SQLite.SQLiteConnection _conn;
private static SQLite.SQLiteConnection Conn
{
get
{
if (_conn == null)
_conn = new SQLite.SQLiteConnection("myPath/datas.lite");
return _conn
}
}
public ItemRepository()
{
Conn.CreateTable<Item>();
}
public Item GetById(int id)
{
return Conn.Get<Item>(id);
}
// Retrieves all items from table Item
public IEnumerable<Item> GetAll()
{
return Conn.Table<Item>();
}
// Updates the provided item
public int InsertOrReplace(Item item)
{
return Conn.InsertOrReplace(item, typeof(Item));
}
}
The app modifies the IsActive property for all items every 5 minutes by updating the Item table (The method TimerHelper.StartTimerInNewThread is called once at startup).
TimerHelper.StartTimerInNewThread(TimeSpan.FromSeconds(delais), ()
=>
{
try
{
// retrieve all items with DB
List<Item> items = repo.GetAll();
foreach (Item item in items)
{
item.IsActive = !item.IsActive;
if (repo.InsertOrReplace(item) == 1)
{
Log?.Info($"Item {item} has been updated in DB: IsActive = {repo.GetItem(item).IsActive}.");
}
else
{
throw new Exception($"InsertOrReplace() method returned a value != 1.");
}
}
}
catch (Exception ex)
{
// Log exception here
}
});
And immediately after updating the rows of table Item, I check (I log every IsActive property value for every Item) that the IsActive property of all items actually changed. So far, so good.
But if I let the application runs for several hours, sometimes, the check does not reflect the previous update...for instance, the application set the IsActive property for all items to TRUE, but the immediate request to the IsActive property returns FALSE for all items.
If I read via DbBrowser for Sqlite the table Item from the database local file (datas.lite), every item has its IsActive property set to TRUE, which is correct. So why the immediate read request I made after the update returned FALSE for all items, is there any caching that is active with sqlite? Or is it due to the fact that I have a static connection, and it is never closed, (it is moreover the recommanded way of doing according to microsoft documentation: https://learn.microsoft.com/en-us/xamarin/get-started/quickstarts/database?pivots=windows)
Thank you for any help
Here is how to protect timer code from being re-entered while it is still running.
Compare these three ways of running code repeatedly using a timer.
This is "typical" timer code. "seconds" is the time interval at which the work is done. Works fine if the code always finishes before the timer delay fires it again. Problematic if the timer code might take the ENTIRE time interval. (or if some background work, such as GC, takes enough time that your timer code eats the remaining time.) Really problematic if timer code takes so long that timer events start "piling up", starving the rest of your app from getting any time.
TYPICAL "NAIVE" TIMER CODE:
// Works fine if action is shorter than time delay.
// DON'T USE THIS CODE, if action might take longer than time delay.
using Timer = System.Timers.Timer;
private void StartFixedDelayTimer(float seconds, Action action)
{
_timer = new Timer(1000 * seconds);
_timer.Elapsed += (sender, e) => action();
// The timer event repeats until explicitly stopped.
_timer.Start();
}
SKIP-IF-BUSY TIMER CODE:
This is similar, but it protects itself by "skipping" work, if the work is still being done:
// For long running "action", increase "idleSeconds" to guarantee more time for other background tasks.
private void StartFixedDelayTimerSkipIfBusy(float seconds, Action action, float idleSeconds = 0.1f)
{
_timer = new Timer(1000 * seconds);
bool entered = false;
_timer.Elapsed += (sender, e) => {
if (entered)
// Timer code already running! Skip this one.
return;
entered = true;
try {
action();
// IMPORTANT: This is needed to "see and skip" next timer event,
// if it happens during "action". Without this, timer events can "pile up",
// starving other background tasks.
System.Threading.Thread.Sleep((int)(1000 * idleSeconds));
} finally {
entered = false;
}
};
// The timer event repeats until explicitly stopped.
_timer.Start();
}
VARIABLE-DELAY TIMER CODE:
This is an alternative approach. It doesn't request that the work be done again, until AFTER it finishes the first time. Here "seconds" is the amount of time between FINISHING the work, and the start of the next work. This is useful if you don't need the work done on a rigorous clock schedule. It has the advantage that no matter how long "action" takes, the rest of your app code gets "seconds" of cpu time before this work starts again - won't "starve" your app.
private void StartDelayBetweenWorkTimer(float seconds, Action action)
{
_timer = new Timer(1000 * seconds);
// Only fire the timer once. (But in Elapsed, we fire it again.)
_timer.AutoReset = false;
_timer.Elapsed += (sender, e) => {
action();
// Fire the timer again. Work will be done again "seconds" seconds after this statement is called.
_timer.Start();
};
_timer.Start();
}
I need to capture the time a user spends on a page in my application.
I wish the time is in hour: minutes: seconds.
Using this I can track the user activities. I do some research but didn't found anything useful.
Is there any way to track the time a user spends on a page?
use a Stopwatch
Stopwatch timer;
protected override void OnAppearing()
{
timer = new Stopwatch();
timer.Start();
}
protected override void OnDisappearing()
{
timer.Stop();
TimeSpan ts = timer.Elapsed;
string elapsedTime = String.Format("{0:00}:{1:00}:{2:00}",
ts.Hours, ts.Minutes, ts.Seconds);
}
Context
We have a service that is dependent on CosmosDB. We created a class, having a lazy container, that will be initialized on startup. In the startup class we do :
CreateDatabaseIfNotExist
CreateContainerIfNotExistsAsync
Problem
The first request to CosmosDB starts the initialization.
When we have multiple threads starting up before the initialization, waiting for this lazy intialization to finish, the intialization takes longer the more threads are waiting for it.
Expected
When multiple threads starting up, the threads that need to have this initialized container, should not impact the initialization duration, since this is in a locked context (lazy)
In the code example below, when changing the amount of threads to 5, the initialization is in a couple of seconds. the higher the count of threads, the higher the duration of the initialization.
code example:
using System;
using System.Diagnostics;
using System.Threading.Tasks;
using Microsoft.Azure.Cosmos;
namespace LazyCosmos.Anon
{
class Program
{
static void Main(string[] args)
{
new Do().Run().GetAwaiter().GetResult();
}
public class Do
{
private Lazy<Container> lazyContainer;
private Container Container => lazyContainer.Value;
public Do()
{
lazyContainer = new Lazy<Container>(() => InitializeContainer().GetAwaiter().GetResult());
}
public async Task Run()
{
try
{
var tasks = new Task[100];
for (int i = 0; i < 100; i++)
{
tasks[i] = Task.Run(() =>
ReadItemAsync<Item>("XXX", "XXX"));
}
await Task.WhenAll(tasks);
}
catch (Exception e)
{
Console.WriteLine(e);
throw;
}
}
public async Task<T> ReadItemAsync<T>(string id, string partitionKey)
{
var itemResponse = await Container.ReadItemAsync<T>(id, new PartitionKey(partitionKey));
return itemResponse.Resource;
}
private async Task<Container> InitializeContainer()
{
var s = Stopwatch.StartNew();
Console.WriteLine($"Started {s.ElapsedMilliseconds}s");
var configuration = new CosmosDbServiceConfiguration("XXX", null, collectionId: "XXX",
"XXX", 400);
var _cosmosClient = new ColdStorageCosmosClient(new ActorColdStorageConfiguration("XXX", "XXX", "https://XXX.XX", "XXX"));
var database = await _cosmosClient
.CreateDatabaseIfNotExistsAsync(configuration.DatabaseId, configuration.DatabaseThroughput);
Console.WriteLine($"CreateDatabaseIfNotExistsAsync took {s.ElapsedMilliseconds}s");
var containerProperties = new ContainerProperties
{
Id = configuration.ContainerId,
PartitionKeyPath = $"/{configuration.PartitionKey}",
DefaultTimeToLive = configuration.DefaultTimeToLive
};
var db = (Database)database;
var containerIfNotExistsAsync = await db.CreateContainerIfNotExistsAsync(containerProperties, configuration.ContainerThroughput);
s.Stop();
Console.WriteLine($"CreateContainerIfNotExistsAsync took {s.ElapsedMilliseconds}s");
return containerIfNotExistsAsync;
}
}
}
public class CosmosDbServiceConfiguration
{
public CosmosDbServiceConfiguration(string databaseId, int? databaseThroughput, string collectionId, string partitionKey, int? containerThroughput = null)
{
DatabaseId = databaseId;
ContainerId = collectionId;
DatabaseThroughput = databaseThroughput;
ContainerThroughput = containerThroughput;
PartitionKey = partitionKey;
}
public string DatabaseId { get; }
public int? DatabaseThroughput { get; }
public string ContainerId { get; }
public int? ContainerThroughput { get; }
public string PartitionKey { get; }
public int? DefaultTimeToLive { get; set; }
}
public class ColdStorageCosmosClient : CosmosClient
{
public ColdStorageCosmosClient(ActorColdStorageConfiguration actorColdStorageConfiguration) : base(actorColdStorageConfiguration.EndpointUrl, actorColdStorageConfiguration.Key)
{
}
}
public class ActorColdStorageConfiguration
{
public ActorColdStorageConfiguration(string databaseName, string collectionName, string endpointUrl, string key)
{
DatabaseName = databaseName;
CollectionName = collectionName;
EndpointUrl = endpointUrl;
Key = key;
}
public string DatabaseName { get; }
public string CollectionName { get; }
public string EndpointUrl { get; }
public string Key { get; }
}
public class Item
{
public string id { get; set; }
}
}
You're experiencing thread pool exhaustion. There's a few different concepts that are conflicting to cause the exhaustion.
First, even though asynchronous code does not use a thread for the duration of the asynchronous operation, it often does need to very briefly borrow a thread pool thread in order to do housework when the asynchronous operation completes. As a result, most asynchronous code only runs efficiently if there is a free thread pool thread available, and if there are no thread pool threads available, then asynchronous code may be delayed.
Another part of the puzzle is that the thread pool has a limited thread injection rate. This is deliberate, so that the thread pool isn't constantly creating/destroying threads as its load varies. That would be very inefficient. Instead, a thread pool that has all of its threads busy (and still has more work to do) will only add a thread every few seconds.
The final concept to recognize is that Lazy<T> is blocking when using the default LazyThreadSafetyMode.ExecutionAndPublication behavior. The way this Lazy<T> works is that only one thread executes the delegate (() => InitializeContainer().GetAwaiter().GetResult()). All other threads block, waiting for that delegate to complete.
So now, putting it all together:
A large number of work items are placed onto the thread pool work queue (by Task.Run). The thread pool begins executing only as many work items as it has threads.
Each of these work items accesses the Container (i.e., Lazy<Container>.Value), so each one of these work items blocks a thread until the initialization is complete. Only the first work item accessing Container will run the initialization code.
The (asynchronous) initialization code attempts to make progress, but it needs a thread pool thread to be free in order to handle housekeeping when its awaits complete. So it is also queueing very small work items to the thread pool as necessary.
The thread pool has more work than it can handle, so it begins adding threads. Since it has a limited thread injection rate, it will only add a thread every few seconds.
The thread pool is overwhelmed with work, but it can't know which work items are the important ones. Most of its work items will just block on the Lazy<T>, which uses up another thread. The thread pool cannot know which work items are the ones from the asynchronous initialization code that will free up the other work items (and threads). So most of the threads added by the thread pool just end up blocking on other work that is having a hard time to complete since there are no thread pool threads available.
So, let's talk solutions.
IMO, the easiest solution is to remove (most of) the blocking. Allow the initialization to be asynchronous by changing the lazy type from Lazy<Container> to Lazy<Task<Container>>. The Lazy<Task<T>> pattern is "asynchronous lazy initialization", and it works by Lazy-initializing a task.
The Lazy<T> part of Lazy<Task<T>> ensures that only the first caller begins executing the asynchronous initialization code. As soon as that asynchronous code yields at an await (and thus returns a Task), the Lazy<T> part is done. So the blocking of other threads is very brief.
Then all the work items get the same Task<T>, and they can all await it. A single Task<T> can be safely awaited any number of times. Once the asynchronous initialization code is complete, the Task<T> gets a result, and all the awaiting work items can continue executing. Any future calls to the Lazy<Task<T>>.Value will immediately get a completed Task<T> which takes no time at all to await since it is already completed.
Once you wrap your head around Lazy<Task<T>>, it's pretty straightforward to use. The only awkward part is that the code for the work items now have to await the shared asynchronous initialization:
public class Do
{
private Lazy<Task<Container>> lazyContainer;
private Task<Container> ContainerTask => lazyContainer.Value;
public Do()
{
lazyContainer = new Lazy<Task<Container>>(InitializeContainer);
}
public async Task<T> ReadItemAsync<T>(string id, string partitionKey)
{
// This is the awkward part. Until you get used to it. :)
var container = await ContainerTask;
var itemResponse = await container.ReadItemAsync<T>(id, new PartitionKey(partitionKey));
return itemResponse.Resource;
}
// other methods are unchanged.
}
I have an AsyncLazy<T> type in my AsyncEx library, which is essentially the same as Lazy<Task<T>> with a few usability enhancements.
More information on this pattern:
Asynchronous lazy initialization blog post.
Recipe 14.1 "Initializing Shared Resources" in my book Concurrency in C# Cookbook, 2nd edition.
The Lazy<Task<T>> asynchronous lazy initialization pattern works great if you have a widely shared resource that may or may not need to be initialized. If you have a local resource (like a private member as in this example), and if you know you will always want it initialized, then you can make the code simpler by just using Task<T> instead of Lazy<Task<T>>:
public class Do
{
private Task<Container> ContainerTask;
public Do()
{
// Important semantic change:
// This begins initialization *immediately*.
// It does not wait for work items to request the container.
ContainerTask = InitializeContainer();
}
public async Task<T> ReadItemAsync<T>(string id, string partitionKey)
{
var container = await ContainerTask;
var itemResponse = await container.ReadItemAsync<T>(id, new PartitionKey(partitionKey));
return itemResponse.Resource;
}
// other methods are unchanged.
}
I'm trying to send an int variable which is continuously updated in a for loop. Inside the for loop, data is published to an observable. Since the variable is incremented in a blocking call, and I want to fetch this value in my reactiveX subscription method. Note: I don't want to add this variable to my async data stream (i.e., without sending this value with publisher.onNext() method).
after incrementing the int variable and publishing to observable in each iteration of for loop, I call wait() on an object. In the subscription consumption, I fetch the value of variable and then notify() the same object. I get the exception 'Async loop interrupted'
public int var=0;
main(String[] args) {
for loop {
variable++;
publisher.onNext(args[0]);
//call wait on a thread to make sure current value of 'var'
//is picked in the getSubscriber() method
wait();
}
}
public Subscriber<T> getSubscriber() {
return new Subscriber<Inference>() {
#Override public void onCompleted() {}
#Override public void onError(Throwable e) {
e.printStackTrace();
}
#Override public void onNext(Inference infer) {
//do something
sysout(var);
//call notify on the thread to resume control in for
//loop
notify();
}
};
}
Just have to call the wait() and notify() in synchronized blocks and it works.
I've heard its bad to use ThreadPool in asp.net, however I've used it for the purpose of educating myself. My goal was to determine if the Application_Error event got fired (which is handled in the Global.asax) - my answer to that is: no, it does not get triggered.
But I had observed something strange. The thread I wrote simply queued up tasks to the threadpool. The task was meant to throw errors randomly. But I observed however that I keep frequently getting the error - the number exceeds the no. of times I've queued the task. A separate concern I have is even the System.Diagnostics.Trace.WriteLine() isn't logging messages to my output window (visual studio). Why this strange behaviour?
using System;
using System.Threading;
namespace ThreadPoolDemo.Web
{
public partial class _default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
}
protected void Button1_Click(object sender, EventArgs e)
{
Thread t = new Thread(createthreads);
t.IsBackground = true;
t.Start();
}
void createthreads()
{
Thread.Sleep(10 * 1000);
int i;
System.Diagnostics.Trace.WriteLine("Queueing items");
for (i = 0; i < 1; i++)
ThreadPool.QueueUserWorkItem(new WaitCallback(ErrorTask), null);
System.Diagnostics.Trace.WriteLine("End Queueing items");
}
void ErrorTask(object obj)
{
Random generator = new Random();
int value = generator.Next(1);
if (value == 0)
throw new Exception("Sample exception thrown");
else
System.Diagnostics.Trace.WriteLine("Processed thread");
}
}
}
There are two problems with your ErrorTask. The first is that you're initializing a new Random instance every time the method is called. The default Random constructor seeds the random number generator with the value from Environment.TickCount, which will likely be the same for consecutive threads. So you'll get the same random sequence for multiple threads.
The bigger problem, though, is that generator.Next(1) will always return 0. Random.Next(int max) generates a random number, N, such that 0 <= N < max. So your ErrorTask will throw the exception for every thread.
I have no idea how or why it would be throwing that exception more than once per call to ErrorTask. That doesn't seem possible.
I would suggest the following modification:
private Random generator = new Random();
void ErrorTask(object obj)
{
int value;
lock (generator)
{
value = generator.Next(2);
}
if (value == 0)
throw new Exception("Sample exception thrown");
else
System.Diagnostics.Trace.WriteLine("Processed thread");
}
generator now has class scope and is initialized only once. The lock is there to prevent multiple threads from trying to generate a number at the same time. Without the lock, the random number generator can get corrupted and it will start returning 0 on every call. And I changed the parameter to generator.Next to 2, so you can get numbers 0 and 1.