For those wondering PeriodicTimer is in System.Threading namespace
@skypravda Жыл бұрын
Thank you bro!
@morganishere1232 жыл бұрын
I'm doing this for a small project and this EXACTLY what I've been looking for. Thank you!!!
@sheveksmath7022 жыл бұрын
Note: at 5:26, the `!stoppingToken.IsCancellationRequest` condition should come before the call to `WaitForNextTickAsync`, as `WaitForNextTickAsync` throws a TaskCancelled exception when the CancellationSource cancels.
@leandrorighetidesouzabueno32472 жыл бұрын
Thanks!
@Fader1682 жыл бұрын
Hey Nick, you are reading my mind! I was thinking through such a thing just this weekend. You are doing great work for us all. Thank you and keep on streaming )))
@mabakay2 жыл бұрын
System.Threading.Timer works like a metronome (doesn't wait for callback to end before invoking next one), exactly like PeriodicTimer.
@-Chris_2 жыл бұрын
so whats the difference?
@mabakay2 жыл бұрын
@@-Chris_ What I see, API change. You get now possibility to write async code instead callbacks. It also rescue you from callback overlapping (if you don't consider it).
@skichoow2 жыл бұрын
But you can set the AutoReset to false, and it will wait for the callback to end :)
@cheesypufs2 жыл бұрын
How do you do this? Every time I work on something new, Bam! Out comes a Nick Chapsas video on it!
@zbaktube Жыл бұрын
This is useful in situation when your background task is lightweight/you can be sure your tasks finish in time. If you cannot be sure, the very first solution is better as it makes sure it does not overload your system. So, it really depends on what you want to solve, and at what cost (like instead of the first solution, does it worth using throttling?, etc.).
@fredericguertin33642 жыл бұрын
and now I rewrite the code I wrote today using PeriodicTimer instead of Timer.Timer. Merci!
@charlesrayshisleriii2 жыл бұрын
Thank you, I saw mention online of this new timer but did not see any good examples before. This made it simple.
@kelton50202 жыл бұрын
The DispatcherTimer is for use with WPF applications, it schedules work on the Dispatcher thread of your application at a specific priority (WPF Dispatcher Priority, not thread priority). There are multiple priority levels, such as Background, Input, DataBind, Input, Normal, Render, etc. So for example, you could have an event that fires on the Dispatcher thread every 10 seconds at a DispatcherPriority.Background priority level, so that anything else running on the Dispatcher thread currently with a greater priority will take precedence. It's fairly specialized, so while it's possible to replace the functionality using the PeriodicTimer using functions like Dispatcher.Yield, I don't think you'd need/want to in most cases where people are using a DispatcherTimer.
@jakubduch13924 ай бұрын
This video meant great help. Thank you.
@hexoter Жыл бұрын
just love it Nick ,exactly what I was looking for
@mbalaganskiy2 жыл бұрын
Task.Delay is fine when all you care is interval between runs
@PauloWirth2 жыл бұрын
That being said, I can't use it to register and schedule multiple background services, is that correct?
@mbalaganskiy2 жыл бұрын
@@PauloWirth you can, periodic timer will synchronise them allowing only one to do the job at any moment in time
@PauloWirth2 жыл бұрын
@@mbalaganskiy I will try it out, I have an implementation using Cron expressions based on the IHostedService interface, which contains a System.Timers.Timer. I intend to test the PeriodicTimer implementation with a new version of my package.
@harvey666162 жыл бұрын
_"PeriodicTimer is effectively a semaphore, allowing only one consumer to work"_ -- that's not how I read the documentation. **"This timer is intended to be used only by a single consumer at a time: only one call to WaitForNextTickAsync(CancellationToken) may be in flight at any given moment."** That sounds like the opposite of a semaphore to me. I.e. a semaphore is specifically designed to support two or more consumers blocking on the semaphore at a time, while PeriodicTimer is explicitly documented as supporting only one at a time.
@mbalaganskiy2 жыл бұрын
@@harvey66616 You're actually correct. I've looked at the source code - there's a guard agains concurrent WaitForNextTickAsync. I've updated my comment.
@cj82-h1y2 жыл бұрын
This is what I do to get around the initial problem: var delayTask = new Task.Delay(5000); await DoWork(); await delayTask; This gets around the missing milliseconds, as the delay starts before the work commences. Works fairly well... not sure if there's an eventual creep, but if you need a pretty good approx of every X seconds, real simple.
@wh33lers2 жыл бұрын
Thank you for sharing. Did not know this timer was introduced already. Looks handy
@margosdesarian Жыл бұрын
Nick you make programming fun again!
@nickbarton31912 жыл бұрын
Brilliant, I used to use a calculated sleep to keep a steady tick. Perhaps that's all that it's doing.
@davidjsutherland2 жыл бұрын
This was a great video. I'm going to watch it again.
@2RWard2 жыл бұрын
Love it. I’ve been hoping I could use this and your description of the console application looks like my use case. Thanks Nick!
2 жыл бұрын
This is nice to know, and quite handy in some situations.
@pattypeppermint3753 Жыл бұрын
I Love you Nick, I Always recommend your Channel at workspace.
@saikumarnarani3900 Жыл бұрын
Thank you Nick. I just can't thank enough
@loganyoung2282 жыл бұрын
I can actually use this. One service I wrote sends reminders to users and it checks whether or not it needs to on a daily basis. Used to be you'd write a windows service for such a thing and you might even do so today, but I wasn't prepared to go through that so I set up a scheduled task in Windows to open a web page every day. As you can guess, this is not ideal but now using this timer, I need only have 1 page open as long as I keep it open anyway. Maybe I can update that scheduled task to check if the window is open lol
@antonmartyniuk2 жыл бұрын
I really like this timer. I have no idea how I missed it earlier in .NET 6
@veec15392 жыл бұрын
when 5 timers is not enough =P, Thanks for video, I'll have a nice timer to play with now.
@tomlee7073 Жыл бұрын
Dont forget that as you cancelled/disposed the CancellationTokenSource you will need to new one up in the Start() method if you are thinking of re-starting the same BackgroundTask instance
@JoseVargas-dx7wz2 жыл бұрын
Nice topic! I use timer in net framework apps and always seemed to me that they are a pain in the ass to deal with. A timer that is awaitable looks like in in synch with the new task sintaxis! I'll be taking a closer look to this for sure.
@robl392 жыл бұрын
In your console app, I believe if an Exception was thrown in the DoWorkAsync method, it would not get thrown until after the task was awaited, which would be after user hit enter and the await task.StopAsync ran
@MetehanG2 жыл бұрын
My main use case for a timer-like thing is a scheduler where I need the "DoWork" method executed at a precise time, i.e. every day at 11 a.m. So for that requirement I have a simple helper method called DelayUntil which calls "await Task.Delay" every 1000 ms until the expected time reached. I am not sure if it is the best practice for such a situation and if I can use this periodic timer to implement a better solution for my requirement but hey, it is simple and it works.
@nickchapsas2 жыл бұрын
Depends on the implementation but it is not a bad practice as long as you don’t have something in the middle that can push the delay further back
@alexisfibonacci2 жыл бұрын
@@nickchapsas And it doesn't chew up CPU cycles?
@amurray049 ай бұрын
PeriodicTimer is great. I remember this workaround in the older days: protected override async Task ExecuteAsync(CancellationToken stoppingToken) { var sw = new Stopwatch(); while(!stoppingToken.IsCancellationRequested) { sw.Start(); // Some long running DoWorkAsync() task (~250ms) await Task.Delay(250, stoppingToken); // Wait for the rest of the second to elapse await Task.Delay(1000 - sw.Elapsed.Milliseconds, stoppingToken); sw.Reset(); } }
@amurray049 ай бұрын
(sorry slightly bad example, misplaced the `sw.Start()`, but you get what I meant!)
@ianknowles2 жыл бұрын
I've always done this by mod of time and compare against a previous which I'm guessing is what the tick is doing under the hood but nice to have a more idiomatic way of doing this...
@anrodse2 жыл бұрын
Exactly. You don't just delay 1000ms. You can store start time, then delay (1000 - ElapsedMiliseconds). There are also other (more complex) ways to do this.
@sameer-ahmed-s Жыл бұрын
@Nick thank for this awesome video on Timer. I have a question on point that you mentioned on 8:11 timeframe that when we have await in the loop then code does not continue. i wanted to understand problem of having await in the loop. Is it possible to explain it with an example. it will be help. Thanks.
@billy65bob2 жыл бұрын
I have used the "Wrong Approach" many times. It's not really wrong; I don't want it to loop at fixed intervals, I just want it to pause briefly between units of work, and for that it's fine. Timer drift is an issue though, and there are again naive but good enough ways to deal with it: If your waits are long, just adjust future sleep and do a catch-up (e.g. if you loop at 60s and the task took 5462ms, then sleep for 54538ms, and factor drift with a stopwatch). If they're short, use a stopwatch to track how far behind schedule you are, and skip some when you're too far behind. This Periodic Timer will skip ticks if the tasks takes too long; if Nick had paused for 1100ms, the task would've executed every 2s, so just be aware of that quirk if you use this.
@hhcosminnet2 жыл бұрын
Chances are you do not want loops piling on top of eachother so this is good.
@billy65bob2 жыл бұрын
@@hhcosminnet everything has a use case.
@MaxReble2 жыл бұрын
Nice video :) what happens if an execption is thrown within the DoWorkAsync method? It won't be passed up, right? So it will repeat forever? And I think you forgot to _timerTask = null in the StopAsync method, this is only needed for sure if you want to reuse this. Therefore you would also need a null check in the StartMethod
@_megazz2 жыл бұрын
This is awesome, Nick. Thank you for sharing.
@CronosTheBearded2 жыл бұрын
Nice I just came across it a few days ago, really happ with it
@buriedstpatrick22942 жыл бұрын
Awesome. Been using third party scheduling libraries to get the same effect. For the stuff I work on they're pretty overkill so this is great!
@kimberlyjacobsen4148 Жыл бұрын
Was spending the day playing with quartz, totally agree this is pure
@SquamishMusqueam2 жыл бұрын
This was a fantastic one! Thanks!
@Elmiger2 жыл бұрын
I like using reactive timers/delays and subscribe to them. No issues with tasks that take longer (since the timer is decoupled from the subscription) and very clean code. What are your thoughts?
@Funestelame2 жыл бұрын
Yup, I'm doing the same when using timers, but reactive is also meant to fix this old school events pattern, so I guess it's no surprise both solution work nicely.
@martink.74972 жыл бұрын
What would be the correct way to have multiple timers in background service? Let's say I want two timers (one with 3s period and second with 5s). Should I fire inside ExecuteAsync two tasks where each handles its own timer and wait for both tasks to finish (when CTS is cancelled). Or going back to old timers with callbacks?
@Astral100 Жыл бұрын
I prefer the first method. Its a lot more important to keep constant delay between operations than to execute them at exactly the same time of a second (or period)
@josephizang61872 жыл бұрын
You rock Nick. awesome stuff
@mangoaaron31462 жыл бұрын
Immediately got rid of my Timer.Timer timers to do background work and replaced with this. Not only is it more accurate, it simplified things being async.
@pavfrang2 жыл бұрын
For precise timing using the ExecuteAsync, the user should use Task.Delay using the time difference between the next DateTime and the current time (and therefore "guarantee" that timing is aligned e.g. per second).
@oM1naE2 жыл бұрын
Be aware that this is not necessarily precise and actually holds a potential surprise... We were actually using a method like that, it seemed to work nicely. However when we ported it to Linux, the method sometimes was invoked several times every interval. Reason was that unlike what we saw ond windows, where the Task would awake with a slight delay, on linux it was awoken a bit early...
@pavfrang2 жыл бұрын
@@oM1naE I agree this is not precise, but this works better than simply delaying a constant value.
@pentanoir2 жыл бұрын
I've never seen this method of starting a new task, that is, by simply assigning the method call to a Task variable. Has this always been possible? Is it a shorthand for Task.StartNew() or have I missed out/misunderstood all this time? Is this considered best practice in async programming for immediately executing a task on the thread pool from a method returning void?
@nickchapsas2 жыл бұрын
It’s always been possible. This is a way to run it in the background without having to immediately await it
@pentanoir2 жыл бұрын
@@nickchapsas Thanks for clarifying! Strange I have never encountered this before, but (yet again) I learned something new watching your videos - thanks man! I can definitely see several use cases for this.
@ivandrofly Жыл бұрын
0:49 - The last timer is for WPF
@kevinc89552 жыл бұрын
Nice job, very cool
@leadscollector2 жыл бұрын
Excellent video. Even some great token work.
@oskioskioski2 жыл бұрын
Why are events and handlers outdated? What should you use instead?
@nickchapsas2 жыл бұрын
Rx or simple Actions/Functions
@denissmith82822 жыл бұрын
In fact, sometimes you need a timer which doesn't count time duration took by the work, like the very first example in this video. Imagine what if the work takes more time than your timer duration. Your work queue will grow infinitely. Instead of that you want to wait 1 second - do the work whatever time it takes - wait 1 second - do the work - do the work whatever time it takes - and so on. Is there some new class for that?
@PauloWirth2 жыл бұрын
Is it possible to register multiple scheduled services using PeriodicTimer and run concurrently? Based on the documentation, it does not seem it is possible.
@jopalesha Жыл бұрын
where i cant find implementation for net framework 4.8?
@winnie86144 ай бұрын
What happens if you miss the time? Like task was exectuted for 1.5 sec?
@bbrinck0932 жыл бұрын
How does this compare to Hangfire? Can you replace Hangfire for basic cron jobs (database manipulation, fetching from apis, ...) by using this?
@izzyblackout10902 жыл бұрын
I can see sometime people use recursion inside DoWork method. What's your opinion on this? Is using "while" loop is better approach?
@Orgbrat2 жыл бұрын
Thanks for sharing. Could this be used in a MAUI application for syncing a SQLite database to a users cloud account on a user defined interval?
@alexisfibonacci2 жыл бұрын
I guess... Perhaps use his sample class as a template and determine when it gets fired up. Being that MAUI supports the Hosting model that now permeates all .NET Core apps, you will get a lot of additional richness with it.
@johnhershberg59152 жыл бұрын
How do you unit test a class that uses this? Do you wrap it in an interface?
@TheCzemike2 жыл бұрын
Would this be appropriate for a heatbeat monitor app? We will potentially have hundreds (or even thousands) of IoT devices deployed that will be sending back heartbeat pings every X seconds and we need to raise an alert if we don't hear the heartbeat in the specified interval (if another heartbeat is heard we cancel the previous countdown to raising an alarm and set a new one). Would this type of timer be good for this scenario or is there a better way to do this?
@KelvinNishikawa2 жыл бұрын
I'm curious as to what happens if the timer interval is shorter than the work operation. Do you get tightly packed back to back calls? Does it drop the calls until the next window elapses? Is there any way to guarantee a specific frequency or call rate?
@nickchapsas2 жыл бұрын
As long as the duration of the execution is shorter than the delay there will be no call rate push back
@thepotion2 ай бұрын
If I have a web app with a BackgroundService and PeriodicTimer and I want to change the timer interval, how do I do it without restarting the web app? Even if you inject IOptionsMonitor you have already initialised the service and timer - any ideas?
@satish82992 жыл бұрын
i have a resource httpClient and i wait until other sync/download processes donot use this httpClient and then the caller can use this httpClient to post a new message. because of a loop inside that waits for the httpClient to be available i cannot use await. How should i code this, a sharing httpClient and somekind of semaphore to indicated that it is in use and the caller that wants to use httpClient should wait.
@hamdimohamed891311 ай бұрын
where can i find the code source please ?
@leotuna2 жыл бұрын
Thank you.
@reumensetechnology93682 жыл бұрын
Hi. I use hangfire for background services. With this periodicTimer, how do u handle skipping concurrent jobs pls
@volodyakachalka518710 ай бұрын
For small projects it can be enough, but for projects where u need advanced scheduling, multiple triggers, CRON's etc. it will not be used.
@KennethSiewersMller2 жыл бұрын
I can't help but think the video miss a mention of IHostedService and the fact that you can add hosted services to a console app by using the generic host builder. Sure, this solution works without the host builder, but if you want DI in a console app, why not use a host builder as well? I might be missing the point though 🙂
@nickchapsas2 жыл бұрын
The point is that people should know how to use a feature without depending on a completely separate one. Knowing how to do those things independendly expands your knowledge scope
@fdhsdrdark2 жыл бұрын
Why using Quartz or Hangfire is a bad decision when a timer operation is needed?
@Masteroxify2 жыл бұрын
What with cases when timer should be created dynamically in various number ? For example, one timer created per one request. Every action should by async, so input all timers to while condition (and use only one at the time) is not expected. Why is Event Handling bad ?
@CentauriDK2 жыл бұрын
Would it also be possible to put such a timer ind a web api to do some tasks at regular intervals?
@nickchapsas2 жыл бұрын
Sure thing
@liski122 жыл бұрын
Really nice! I'm curious how you would implement repeating tasks at a specific scheduled time?
@nickchapsas2 жыл бұрын
You’d have to Task.Delay the TimeSpan which is the delta between now and the time that you want the timer to get triggered
@ruekkart2 жыл бұрын
@@nickchapsas is there something related with Cron expressions?
@Elmiger2 жыл бұрын
@@ruekkart quartz dotnet
@badger2-3832 жыл бұрын
I used NCrontab with a combination of.... what.... uh.. Nick just showed **not** to do . I'm now looking at implementing his approach. I had no idea a new timer was implemented.
@liski122 жыл бұрын
@@nickchapsas Thanks for the answer. That's what I'm already doing, but I was curious if there was any other way, since it's, in the end, keeping the app running, which is really not a good thing for an API. The solution was to have a separate API to do theses scheduled tasks.
@madarchitector8107 Жыл бұрын
I belive you cannot Start and StopAsync task several times in your Console App setup as you call Dispose on your CancellationTokenSource in StopAsync. So you need to recreate it
@jamescanady81562 жыл бұрын
DispatchTimer is used for WPF
@UFOCurrents2 жыл бұрын
Awesome!
@thethreeheadedmonkey2 жыл бұрын
I find that usually I don't want something to happen periodically, as much as I want it to happen on a schedule... to that end, this kind of functionality is *very* rarely used for anything complicated. Maybe for some semi-low level things like reading from a memory channel and processing it in the background at certain intervals.
@davidheale64352 жыл бұрын
That's where I would store some configurable schedules somewhere and have the timer check to see what needs to be executed and spin it off in its own thread.
@thethreeheadedmonkey2 жыл бұрын
@@davidheale6435 I'd probably use a library :-P I'm lazy like that.
@kukublof50572 жыл бұрын
silly question: does anyone know how does he set the output to print to the IDE's output window and not to the console, is it possible to do in VS2022 or only in that JetBrains IDE ?
@ashfaaqriphque2 жыл бұрын
one way is to use Debug.WriteLine instead of Console.WriteLine in a VS2022 console application. This will print the message to the IDE's output window.
@davidreis50862 жыл бұрын
it would be nice if we didn't have to use while, and the task was launched by the periodic timer once the interval expired, then the problem of the work taking more time than the actual interval won't be a problem
@ВладиславДараган-ш3ф2 жыл бұрын
Quartz is still unbeatable tbh
@KeyboardKrieger2 жыл бұрын
Thought the same. Why tinkering myself with this, when there is already such a solid and free solution.
@eagleinthesky97772 жыл бұрын
Those timers are funny until you need to scale your web API and run multiple pods of the same service. And when this is the case, only Hangfire or Quartz can help with proper scheduling.
@alexanderdevteammate81002 жыл бұрын
But why not Quartz?
@nickchapsas2 жыл бұрын
Firstly quartz is pretty archaic. Hangfire is a better solution. That being said there are many times where you just need a small timer and nothing else complicated so this is a better approach for that usecase
@alexanderdevteammate81002 жыл бұрын
@@nickchapsas Thanks for the answer! Took a closer look to hangfire - pretty cool stuff
@markolahma44672 жыл бұрын
Pretty archaic, haven't heard that before. But I think some of that applies to your own advice? Like other streamers having a better solution? Just trying to push you towards having arguments 😉
@ahmetkuris30052 жыл бұрын
I think Coravel works quiet simpler and better than this approach. You can also prevent double executions.
@nertsch77 Жыл бұрын
This class is somehow senseless. Basically it aligns the runs on multiples of the interval. I never had the demand for such an behavior. Usually I wanted a) loop-runtime-compensation, where the Delay time is Max(0, interval-loopRuntime) or b) Delay a fixed amount of time during each run
@mariocamspam722 жыл бұрын
hell yeah
@masonwheeler65362 жыл бұрын
Anyone else get an XKCD 927 vibe from this?
@fatman_slim5 Жыл бұрын
I hate it when people use the Task output of an async method to fork execution and expect it to not block. In my opinion you should never do this, since it can lead to some very confusing behavior. You should really do a _timerTask = Task.Run(...), that would actually have the desired behavior and not block the main thread during Start(). In this example, your main thread is not freed until DoWorkAsync() actually awaits something, and how long is it going to take to do that? who knows... and then all of the sudden your application is hanging for some strange reason when it gets to the Start() line and you don't know why because you think that DoWorkAsync( ) is supposed to just return a Task and continue, when it is actually doing no such thing....
@Vastlee2 жыл бұрын
Nick, can you get some "Nick Specific" merch? I keep looking every few months to see & it's all boring af. If I'm going to drop some bank on a gym tank from someone I like it shouldn't look like I just came from the MS Store. I wanna see some Nick Chapsas: If you like this type of content & want to see more blarbagarbagoogooble Nick Chapsas: Make an array with some random numbers new int[] { 69, 420 } etc, etc
@CesarHernandez-i1l Жыл бұрын
Has anyone noticed that memory usage is constantly increasing when time is very short?
@FiveNineO2 жыл бұрын
A gazzillion ways to do everything…
@bescein2 жыл бұрын
You can achieve the same thing with a regular Stopwatch tbh
@hensou2 жыл бұрын
Example of losing a second (went from 15 to 17) on 3:44
@mmenjic2 жыл бұрын
6:20 😳😳😳 ohhh it is cheating, it tries to match the seconds by subtracting measured delays so your timer is not 1000, instead it is 1000 - x where x is delay/error from previous step.
@winnie86144 ай бұрын
You didn't Dispose timer, this is potentially harmful, if app won't be shutdown anyway.
@ablues159 ай бұрын
1000 milliseconds. If only there were a more succinct way of writing that...