IVSoftware.Portable.WatchdogTimer
1.1.0
There is a newer prerelease version of this package available.
See the version list below for details.
See the version list below for details.
dotnet add package IVSoftware.Portable.WatchdogTimer --version 1.1.0
NuGet\Install-Package IVSoftware.Portable.WatchdogTimer -Version 1.1.0
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="IVSoftware.Portable.WatchdogTimer" Version="1.1.0" />
For projects that support PackageReference, copy this XML node into the project file to reference the package.
paket add IVSoftware.Portable.WatchdogTimer --version 1.1.0
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
#r "nuget: IVSoftware.Portable.WatchdogTimer, 1.1.0"
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
// Install IVSoftware.Portable.WatchdogTimer as a Cake Addin #addin nuget:?package=IVSoftware.Portable.WatchdogTimer&version=1.1.0 // Install IVSoftware.Portable.WatchdogTimer as a Cake Tool #tool nuget:?package=IVSoftware.Portable.WatchdogTimer&version=1.1.0
The NuGet Team does not provide support for this client. Please contact its maintainers for support.
Watchdog timer
A timer designed to complete after the time span set by the Interval
property has elapsed since the most recent call to the StartOrRestart
method. This results in a single completion regardless of the number of restarts. Invoking the Cancel
method negates any enqueued action or event in the queue.
Methods
/// <summary>
/// Restart the watchdog timer.
/// </summary>
/// <remarks>
/// Core method that can take a parameterized action as well as a custom EventArgs object.
/// </remarks>
public void StartOrRestart(Action action, EventArgs e)
{
Running = true;
_wdtCount++;
var capturedCount = _wdtCount;
_isCancelled= false;
Task
.Delay(Interval)
.GetAwaiter()
.OnCompleted(() =>
{
// If the 'captured' localCount has not changed after awaiting the Interval,
// it indicates that no new 'bones' have been thrown during that interval.
if (capturedCount.Equals(_wdtCount) && !_isCancelled)
{
action?.Invoke();
Running = false;
RanToCompletion?.Invoke(this, e ?? EventArgs.Empty);
}
});
}
/// <summary>
/// Restart the watchdog timer.
/// </summary>
/// <remarks>
/// Subscribe to the RanToCompletion event to receive notification of completion.
/// On completion, fire an event with an empty EventArgs object.
/// </remarks>
public void StartOrRestart() => StartOrRestart(null, EventArgs.Empty);
/// <summary>
/// Restart the watchdog timer.
/// </summary>
/// <remarks>
/// Subscribe to the RanToCompletion event to receive notification of completion.
/// On completion, fire an event using a custom parameterized EventArgs object.
/// </remarks>
public void StartOrRestart(EventArgs e) => StartOrRestart(null, e);
/// <summary>
/// Restart the watchdog timer.
/// </summary>
/// <remarks>
/// Subscribe to the RanToCompletion event to receive notification of completion.
/// On completion, invoke a parameterized action.
/// </remarks>
public void StartOrRestart(Action action) => StartOrRestart(action, EventArgs.Empty);
public void Cancel() => _isCancelled = true;
Properties
public TimeSpan Interval { get; set; } = TimeSpan.FromSeconds(1);
public bool Running { get; private set; }
Event
public event EventHandler RanToCompletion;
Usage
Source and demo code is available on the GitHub.
using IVSoftware.Portable;
using System;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
namespace testbench
{
internal class Program
{
static void Main(string[] args)
{
runAsync();
Console.ReadKey();
}
private static async void runAsync()
{
BringConsoleToFront();
// Three second watchdog timer
WatchdogTimer _wdt = new WatchdogTimer { Interval = TimeSpan.FromSeconds(3) };
// System.Diagnostics.Stopwatch for testing purposes.
Stopwatch _stopWatch = new Stopwatch();
#region T E S T A C T I O N
Console.WriteLine("T E S T A C T I O N");
_stopWatch.Start();
Console.WriteLine($"{_stopWatch.Elapsed} START");
_wdt.StartOrRestart(()=> MarkEmailAsRead(id: 1));
await Task.Delay(TimeSpan.FromSeconds(1));
Console.WriteLine(_stopWatch.Elapsed);
_wdt.StartOrRestart(() => MarkEmailAsRead(id: 2));
await Task.Delay(TimeSpan.FromSeconds(1));
Console.WriteLine(_stopWatch.Elapsed);
_wdt.StartOrRestart(() => MarkEmailAsRead(id: 3));
// Should run to completion
await Task.Delay(TimeSpan.FromSeconds(4));
Console.WriteLine(_stopWatch.Elapsed + Environment.NewLine);
_wdt.StartOrRestart(() => MarkEmailAsRead(id: 10));
await Task.Delay(TimeSpan.FromSeconds(2));
Console.WriteLine(_stopWatch.Elapsed);
_wdt.StartOrRestart(() => MarkEmailAsRead(id: 20));
await Task.Delay(TimeSpan.FromSeconds(1));
Console.WriteLine(_stopWatch.Elapsed);
_wdt.StartOrRestart(() => MarkEmailAsRead(id: 30));
// Should run to completion
await Task.Delay(TimeSpan.FromSeconds(4));
Console.WriteLine(_stopWatch.Elapsed + Environment.NewLine);
#endregion T E S T A C T I O N
#region T E S T C A N C E L
Console.WriteLine("T E S T C A N C E L");
_stopWatch.Restart();
Console.WriteLine($"{_stopWatch.Elapsed} START");
_wdt.StartOrRestart(() => MarkEmailAsRead(id: 1), new CustomEventArgs(id: 1));
await Task.Delay(TimeSpan.FromSeconds(1));
Console.WriteLine(_stopWatch.Elapsed);
_wdt.StartOrRestart(() => MarkEmailAsRead(id: 2), new CustomEventArgs(id: 2));
await Task.Delay(TimeSpan.FromSeconds(1));
Console.WriteLine(_stopWatch.Elapsed);
_wdt.StartOrRestart(() => MarkEmailAsRead(id: 3), new CustomEventArgs(id: 3));
// Cancel event and allow enough time to otherwise complete.
await Task.Delay(TimeSpan.FromSeconds(2));
_wdt.Cancel();
await Task.Delay(TimeSpan.FromSeconds(2));
Console.WriteLine(_stopWatch.Elapsed + Environment.NewLine);
_wdt.StartOrRestart(() => MarkEmailAsRead(id: 10), new CustomEventArgs(id: 10));
await Task.Delay(TimeSpan.FromSeconds(2));
Console.WriteLine(_stopWatch.Elapsed);
_wdt.StartOrRestart(() => MarkEmailAsRead(id: 20), new CustomEventArgs(id: 20));
await Task.Delay(TimeSpan.FromSeconds(1));
Console.WriteLine(_stopWatch.Elapsed);
_wdt.StartOrRestart(() => MarkEmailAsRead(id: 30), new CustomEventArgs(id: 30));
// Cancel event and allow enough time to otherwise complete.
await Task.Delay(TimeSpan.FromSeconds(2));
_wdt.Cancel();
await Task.Delay(TimeSpan.FromSeconds(2));
Console.WriteLine(_stopWatch.Elapsed + Environment.NewLine);
#endregion T E S T C A N C E L
#region T E S T E V E N T
_wdt.RanToCompletion += onWdtRanToCompletion;
Console.WriteLine("T E S T E V E N T");
_stopWatch.Restart();
Console.WriteLine($"{_stopWatch.Elapsed} START");
_wdt.StartOrRestart(new CustomEventArgs(id: 1));
await Task.Delay(TimeSpan.FromSeconds(1));
Console.WriteLine(_stopWatch.Elapsed);
_wdt.StartOrRestart(new CustomEventArgs(id: 2));
await Task.Delay(TimeSpan.FromSeconds(1));
Console.WriteLine(_stopWatch.Elapsed);
_wdt.StartOrRestart(new CustomEventArgs(id: 3));
// Should run to completion
await Task.Delay(TimeSpan.FromSeconds(4));
Console.WriteLine(_stopWatch.Elapsed + Environment.NewLine);
Console.WriteLine(_stopWatch.Elapsed);
_wdt.StartOrRestart(new CustomEventArgs(id: 10));
await Task.Delay(TimeSpan.FromSeconds(2));
Console.WriteLine(_stopWatch.Elapsed);
_wdt.StartOrRestart(new CustomEventArgs(id: 20));
await Task.Delay(TimeSpan.FromSeconds(1));
Console.WriteLine(_stopWatch.Elapsed);
_wdt.StartOrRestart(new CustomEventArgs(id: 30));
// Should run to completion
await Task.Delay(TimeSpan.FromSeconds(4));
Console.WriteLine(_stopWatch.Elapsed + Environment.NewLine);
Console.WriteLine($"DONE {_stopWatch.Elapsed}");
#endregion T E S T E V E N T
#region L o c a l F x
void MarkEmailAsRead(int id)
{
Console.WriteLine($"Expired: {_stopWatch.Elapsed}");
Console.WriteLine($"The email with the ID '{id}' has been marked read");
}
void onWdtRanToCompletion(object sender, EventArgs e)
{
if (e is CustomEventArgs ePlus)
{
Console.WriteLine($"Expired: {_stopWatch.Elapsed}");
Console.WriteLine($"The email with the ID '{ePlus.Id}' has been marked read");
}
}
void BringConsoleToFront()
{
SetForegroundWindow(GetConsoleWindow());
}
#endregion L o c a l F x
}
[DllImport("kernel32.dll", ExactSpelling = true)]
public static extern IntPtr GetConsoleWindow();
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
public static extern bool SetForegroundWindow(IntPtr hWnd);
}
class CustomEventArgs : EventArgs
{
public CustomEventArgs(int id)
{
Id = id;
}
public int Id { get; }
}
}
Product | Versions Compatible and additional computed target framework versions. |
---|---|
.NET | net5.0 was computed. net5.0-windows was computed. net6.0 was computed. net6.0-android was computed. net6.0-ios was computed. net6.0-maccatalyst was computed. net6.0-macos was computed. net6.0-tvos was computed. net6.0-windows was computed. net7.0 was computed. net7.0-android was computed. net7.0-ios was computed. net7.0-maccatalyst was computed. net7.0-macos was computed. net7.0-tvos was computed. net7.0-windows was computed. net8.0 was computed. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. |
.NET Core | netcoreapp2.0 was computed. netcoreapp2.1 was computed. netcoreapp2.2 was computed. netcoreapp3.0 was computed. netcoreapp3.1 was computed. |
.NET Standard | netstandard2.0 is compatible. netstandard2.1 was computed. |
.NET Framework | net461 was computed. net462 was computed. net463 was computed. net47 was computed. net471 was computed. net472 was computed. net48 was computed. net481 was computed. |
MonoAndroid | monoandroid was computed. |
MonoMac | monomac was computed. |
MonoTouch | monotouch was computed. |
Tizen | tizen40 was computed. tizen60 was computed. |
Xamarin.iOS | xamarinios was computed. |
Xamarin.Mac | xamarinmac was computed. |
Xamarin.TVOS | xamarintvos was computed. |
Xamarin.WatchOS | xamarinwatchos was computed. |
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.
-
.NETStandard 2.0
- No dependencies.
GitHub repositories
This package is not used by any popular GitHub repositories.
Version | Downloads | Last updated |
---|---|---|
1.3.0-beta | 0 | 10/4/2024 |
1.2.1-beta | 1 | 11/7/2023 |
1.1.0 | 2 | 3/10/2023 |
1.0.2 | 2 | 11/7/2023 |