Scheduling repeating tasks with .NET 6’s NEW Timer

Поделиться
HTML-код
  • Опубликовано: 15 ноя 2024

Комментарии • 137

  • @morganishere123
    @morganishere123 2 года назад +7

    I'm doing this for a small project and this EXACTLY what I've been looking for. Thank you!!!

  • @KoScosss
    @KoScosss 2 года назад +83

    For those wondering PeriodicTimer is in System.Threading namespace

  • @mabakay
    @mabakay 2 года назад +8

    System.Threading.Timer works like a metronome (doesn't wait for callback to end before invoking next one), exactly like PeriodicTimer.

    • @-Chris_
      @-Chris_ 2 года назад +1

      so whats the difference?

    • @mabakay
      @mabakay 2 года назад +2

      ​@@-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).

    • @skichoow
      @skichoow 2 года назад +2

      But you can set the AutoReset to false, and it will wait for the callback to end :)

  • @zbaktube
    @zbaktube Год назад +3

    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.).

  • @Fader168
    @Fader168 2 года назад +7

    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 )))

  • @cheesypufs
    @cheesypufs 2 года назад +3

    How do you do this? Every time I work on something new, Bam! Out comes a Nick Chapsas video on it!

  • @fredericguertin3364
    @fredericguertin3364 2 года назад +1

    and now I rewrite the code I wrote today using PeriodicTimer instead of Timer.Timer. Merci!

  • @jakubduch1392
    @jakubduch1392 3 месяца назад

    This video meant great help. Thank you.

  • @mbalaganskiy
    @mbalaganskiy 2 года назад +17

    Task.Delay is fine when all you care is interval between runs

    • @PauloWirth
      @PauloWirth 2 года назад

      That being said, I can't use it to register and schedule multiple background services, is that correct?

    • @mbalaganskiy
      @mbalaganskiy 2 года назад

      @@PauloWirth you can, periodic timer will synchronise them allowing only one to do the job at any moment in time

    • @PauloWirth
      @PauloWirth 2 года назад

      @@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.

    • @harvey66616
      @harvey66616 2 года назад +1

      _"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.

    • @mbalaganskiy
      @mbalaganskiy 2 года назад

      @@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-h1y
    @cj82-h1y 2 года назад +4

    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.

  • @sheveksmath702
    @sheveksmath702 2 года назад +9

    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.

  • @charlesrayshisleriii
    @charlesrayshisleriii 2 года назад

    Thank you, I saw mention online of this new timer but did not see any good examples before. This made it simple.

  • @kelton5020
    @kelton5020 2 года назад +2

    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.

  • @wh33lers
    @wh33lers 2 года назад +3

    Thank you for sharing. Did not know this timer was introduced already. Looks handy

  • @nickbarton3191
    @nickbarton3191 2 года назад

    Brilliant, I used to use a calculated sleep to keep a steady tick. Perhaps that's all that it's doing.

  • @hexoter
    @hexoter 11 месяцев назад

    just love it Nick ,exactly what I was looking for

  • @pattypeppermint3753
    @pattypeppermint3753 Год назад

    I Love you Nick, I Always recommend your Channel at workspace.

  • @antonmartyniuk
    @antonmartyniuk 2 года назад +3

    I really like this timer. I have no idea how I missed it earlier in .NET 6

  • @tomlee7073
    @tomlee7073 Год назад +2

    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

  • @saikumarnarani3900
    @saikumarnarani3900 11 месяцев назад

    Thank you Nick. I just can't thank enough

  • @loganyoung228
    @loganyoung228 2 года назад

    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

  • @margosdesarian
    @margosdesarian Год назад

    Nick you make programming fun again!

  • @robl39
    @robl39 2 года назад +1

    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

  •  2 года назад +1

    This is nice to know, and quite handy in some situations.

  • @ianknowles
    @ianknowles 2 года назад +5

    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...

    • @anrodse
      @anrodse 2 года назад

      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.

  • @amurray04
    @amurray04 8 месяцев назад

    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();
    }
    }

    • @amurray04
      @amurray04 8 месяцев назад

      (sorry slightly bad example, misplaced the `sw.Start()`, but you get what I meant!)

  • @davidjsutherland
    @davidjsutherland 2 года назад

    This was a great video. I'm going to watch it again.

  • @mangoaaron3146
    @mangoaaron3146 2 года назад +2

    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.

  • @veec1539
    @veec1539 2 года назад +1

    when 5 timers is not enough =P, Thanks for video, I'll have a nice timer to play with now.

  • @billy65bob
    @billy65bob 2 года назад +1

    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.

    • @hhcosminnet
      @hhcosminnet 2 года назад

      Chances are you do not want loops piling on top of eachother so this is good.

    • @billy65bob
      @billy65bob 2 года назад

      @@hhcosminnet everything has a use case.

  • @2RWard
    @2RWard 2 года назад

    Love it. I’ve been hoping I could use this and your description of the console application looks like my use case.
    Thanks Nick!

  • @JoseVargas-dx7wz
    @JoseVargas-dx7wz 2 года назад

    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.

  • @martink.7497
    @martink.7497 2 года назад +1

    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?

  • @MetehanG
    @MetehanG 2 года назад +1

    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.

    • @nickchapsas
      @nickchapsas  2 года назад +4

      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

    • @alexisfibonacci
      @alexisfibonacci 2 года назад

      @@nickchapsas And it doesn't chew up CPU cycles?

  • @SquamishMusqueam
    @SquamishMusqueam 2 года назад

    This was a fantastic one! Thanks!

  • @pavfrang
    @pavfrang 2 года назад

    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).

    • @oM1naE
      @oM1naE 2 года назад +1

      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...

    • @pavfrang
      @pavfrang 2 года назад

      @@oM1naE I agree this is not precise, but this works better than simply delaying a constant value.

  • @buriedstpatrick2294
    @buriedstpatrick2294 2 года назад

    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
      @kimberlyjacobsen4148 Год назад

      Was spending the day playing with quartz, totally agree this is pure

  • @Astral100
    @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)

  • @_megazz
    @_megazz 2 года назад

    This is awesome, Nick. Thank you for sharing.

  • @CronosTheBearded
    @CronosTheBearded 2 года назад

    Nice I just came across it a few days ago, really happ with it

  • @sameer-ahmed-s
    @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.

  • @leandrorighetidesouzabueno3247
    @leandrorighetidesouzabueno3247 2 года назад

    Thanks!

  • @josephizang6187
    @josephizang6187 2 года назад

    You rock Nick. awesome stuff

  • @MaxReble
    @MaxReble 2 года назад +4

    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

  • @pentanoir
    @pentanoir 2 года назад +2

    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?

    • @nickchapsas
      @nickchapsas  2 года назад +2

      It’s always been possible. This is a way to run it in the background without having to immediately await it

    • @pentanoir
      @pentanoir 2 года назад

      @@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.

  • @bbrinck093
    @bbrinck093 2 года назад

    How does this compare to Hangfire? Can you replace Hangfire for basic cron jobs (database manipulation, fetching from apis, ...) by using this?

  • @thepotion
    @thepotion 21 день назад

    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?

  • @ivandrofly
    @ivandrofly Год назад

    0:49 - The last timer is for WPF

  • @Orgbrat
    @Orgbrat 2 года назад +1

    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?

    • @alexisfibonacci
      @alexisfibonacci 2 года назад

      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.

  • @reumensetechnology9368
    @reumensetechnology9368 2 года назад

    Hi. I use hangfire for background services. With this periodicTimer, how do u handle skipping concurrent jobs pls

  • @kevinc8955
    @kevinc8955 2 года назад

    Nice job, very cool

  • @leotuna
    @leotuna 2 года назад

    Thank you.

  • @leadscollector
    @leadscollector 2 года назад

    Excellent video. Even some great token work.

  • @jamescanady8156
    @jamescanady8156 2 года назад

    DispatchTimer is used for WPF

  • @winnie8614
    @winnie8614 3 месяца назад

    What happens if you miss the time? Like task was exectuted for 1.5 sec?

  • @volodyakachalka5187
    @volodyakachalka5187 8 месяцев назад

    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.

  • @PauloWirth
    @PauloWirth 2 года назад

    Is it possible to register multiple scheduled services using PeriodicTimer and run concurrently? Based on the documentation, it does not seem it is possible.

  • @KelvinNishikawa
    @KelvinNishikawa 2 года назад +1

    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?

    • @nickchapsas
      @nickchapsas  2 года назад +1

      As long as the duration of the execution is shorter than the delay there will be no call rate push back

  • @izzyblackout1090
    @izzyblackout1090 2 года назад

    I can see sometime people use recursion inside DoWork method. What's your opinion on this? Is using "while" loop is better approach?

  • @jopalesha
    @jopalesha Год назад

    where i cant find implementation for net framework 4.8?

  • @johnhershberg5915
    @johnhershberg5915 2 года назад

    How do you unit test a class that uses this? Do you wrap it in an interface?

  • @TheCzemike
    @TheCzemike 2 года назад

    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?

  • @satish8299
    @satish8299 2 года назад

    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.

  • @Elmiger
    @Elmiger 2 года назад +8

    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?

    • @Funestelame
      @Funestelame 2 года назад +1

      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.

  • @KennethSiewersMller
    @KennethSiewersMller 2 года назад +1

    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 🙂

    • @nickchapsas
      @nickchapsas  2 года назад +3

      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

  • @denissmith8282
    @denissmith8282 2 года назад

    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?

  • @CentauriDK
    @CentauriDK 2 года назад

    Would it also be possible to put such a timer ind a web api to do some tasks at regular intervals?

  • @hamdimohamed8913
    @hamdimohamed8913 10 месяцев назад

    where can i find the code source please ?

  • @thethreeheadedmonkey
    @thethreeheadedmonkey 2 года назад

    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.

    • @davidheale6435
      @davidheale6435 2 года назад +1

      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.

    • @thethreeheadedmonkey
      @thethreeheadedmonkey 2 года назад

      @@davidheale6435 I'd probably use a library :-P I'm lazy like that.

  • @fdhsdrdark
    @fdhsdrdark 2 года назад

    Why using Quartz or Hangfire is a bad decision when a timer operation is needed?

  • @oskioskioski
    @oskioskioski 2 года назад +2

    Why are events and handlers outdated? What should you use instead?

    • @nickchapsas
      @nickchapsas  2 года назад +1

      Rx or simple Actions/Functions

  • @Masteroxify
    @Masteroxify 2 года назад

    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 ?

  • @kukublof5057
    @kukublof5057 2 года назад

    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 ?

    • @ashfaaqriphque
      @ashfaaqriphque 2 года назад +1

      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.

  • @UFOCurrents
    @UFOCurrents 2 года назад

    Awesome!

  • @liski12
    @liski12 2 года назад

    Really nice! I'm curious how you would implement repeating tasks at a specific scheduled time?

    • @nickchapsas
      @nickchapsas  2 года назад +2

      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

    • @ruekkart
      @ruekkart 2 года назад

      ​​@@nickchapsas is there something related with Cron expressions?

    • @Elmiger
      @Elmiger 2 года назад +8

      @@ruekkart quartz dotnet

    • @badger2-383
      @badger2-383 2 года назад

      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.

    • @liski12
      @liski12 2 года назад

      @@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
    @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

  • @davidreis5086
    @davidreis5086 2 года назад

    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

  • @masonwheeler6536
    @masonwheeler6536 Год назад

    Anyone else get an XKCD 927 vibe from this?

  • @ВладиславДараган-ш3ф
    @ВладиславДараган-ш3ф 2 года назад +2

    Quartz is still unbeatable tbh

    • @KeyboardKrieger
      @KeyboardKrieger 2 года назад

      Thought the same. Why tinkering myself with this, when there is already such a solid and free solution.

  • @eagleinthesky9777
    @eagleinthesky9777 2 года назад

    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.

  • @mariocamspam72
    @mariocamspam72 2 года назад

    hell yeah

  • @nertsch77
    @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

  • @ahmetkuris3005
    @ahmetkuris3005 2 года назад

    I think Coravel works quiet simpler and better than this approach. You can also prevent double executions.

  • @fatman_slim5
    @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....

  • @Vastlee
    @Vastlee 2 года назад

    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
    @CesarHernandez-i1l Год назад

    Has anyone noticed that memory usage is constantly increasing when time is very short?

  • @alexanderdevteammate8100
    @alexanderdevteammate8100 2 года назад

    But why not Quartz?

    • @nickchapsas
      @nickchapsas  2 года назад +1

      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

    • @alexanderdevteammate8100
      @alexanderdevteammate8100 2 года назад

      @@nickchapsas Thanks for the answer!
      Took a closer look to hangfire - pretty cool stuff

    • @markolahma4467
      @markolahma4467 2 года назад

      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 😉

  • @FiveNineO
    @FiveNineO 2 года назад

    A gazzillion ways to do everything…

  • @bescein
    @bescein 2 года назад

    You can achieve the same thing with a regular Stopwatch tbh

  • @hensou
    @hensou 2 года назад

    Example of losing a second (went from 15 to 17) on 3:44

  • @winnie8614
    @winnie8614 3 месяца назад

    You didn't Dispose timer, this is potentially harmful, if app won't be shutdown anyway.

  • @mmenjic
    @mmenjic 2 года назад

    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.

  • @ablues15
    @ablues15 8 месяцев назад

    1000 milliseconds. If only there were a more succinct way of writing that...

  • @paulegan3783
    @paulegan3783 Год назад

    Thanks!

  • @jacobphillips9235
    @jacobphillips9235 Год назад

    Thanks!

  • @somke
    @somke 9 месяцев назад

    Thanks!