Windowsアプリケーション開発において、定期的または特定のイベントに基づいて処理を実行する必要がある場面は少なくありません。Windowsには標準で「タスクスケジューラ」が搭載されていますが、これを.NETアプリケーションからプログラム的に操作するのは少々複雑です。
そこで役立つのが、オープンソースライブラリ「TaskScheduler」です。このライブラリは、Windowsタスクスケジューラに対する.NETラッパーを提供し、複数バージョンへの対応、エディタ機能、ローカライズサポートなどを通じて、タスクの作成、管理、実行をC#などの.NET言語から直感的かつ強力に行えるように設計されています。本記事では、TaskSchedulerライブラリの基本的な使い方から、その応用例までを解説します。
プロジェクトの初期設定
ライブラリのインストール
TaskSchedulerライブラリの利用を開始するには、まずNuGetパッケージマネージャーを通じてプロジェクトにインストールします。Visual Studioのパッケージマネージャーコンソールで、以下のコマンドを実行してください。
Install-Package TaskScheduler
Windowsタスクスケジューラへのタスク登録例
ここでは、TaskSchedulerライブラリを使用して、Windowsタスクスケジューラに新しいタスクを登録する具体的な手順を示します。この例では、現在時刻を一時ファイルに出力する簡単なコマンドを実行するタスクを作成し、それを毎日特定の時間に実行するタスクとして登録・削除します。
using System;
using System.Diagnostics;
using System.IO;
using Microsoft.Win32.TaskScheduler; // TaskSchedulerライブラリの正しい名前空間
class Program
{
const string TaskIdentifier = "DailyLogOutputTask";
const string TaskDetail = "毎日、指定された時間にシステム情報を一時ログファイルに出力するサンプルタスク。";
const string TaskProgramPath = "cmd.exe";
const string TaskCommandArgs = "/c echo %DATE% %TIME% System info output >> \"%TEMP%\\scheduled_task_output.log\" && echo タスクが実行されました。";
const int ExecutionHour = 10; // 例: 毎日午前10時に実行
static void Main(string[] args)
{
try
{
Console.WriteLine("Windowsタスクスケジューラへのタスク登録を開始します。");
// タスクサービスに接続
using (TaskService service = new TaskService())
{
// 同じ名前のタスクが既に存在するか確認し、存在する場合は削除
if (service.GetTask(TaskIdentifier) != null)
{
service.RootFolder.DeleteTask(TaskIdentifier);
Console.WriteLine($"既存のタスク '{TaskIdentifier}' を削除しました。");
}
// 新しいタスク定義を作成
TaskDefinition definition = service.NewTask();
definition.RegistrationInfo.Description = TaskDetail;
definition.RegistrationInfo.Author = "SampleApplication";
// 毎日午前10時にトリガーを設定
DailyTrigger trigger = new DailyTrigger();
trigger.StartBoundary = DateTime.Today + TimeSpan.FromHours(ExecutionHour);
definition.Triggers.Add(trigger);
// タスク実行時のアクションを設定 (コマンドプロンプトで日付と時刻をファイル出力)
ExecAction action = new ExecAction(TaskProgramPath, TaskCommandArgs);
definition.Actions.Add(action);
// タスクを登録(インタラクティブユーザーで最高権限で実行)
definition.Principal.LogonType = TaskLogonType.InteractiveToken;
definition.Principal.RunLevel = TaskRunLevel.Highest;
service.RootFolder.RegisterTaskDefinition(TaskIdentifier, definition);
Console.WriteLine($"タスク '{TaskIdentifier}' が登録されました。");
Console.WriteLine($"毎日午前{ExecutionHour}時に実行されます。出力は %TEMP%\\scheduled_task_output.log に記録されます。");
Console.WriteLine("Windowsタスクスケジューラを開いて確認できます。");
Console.WriteLine("何かキーを押すと、タスクを削除してアプリケーションを終了します...");
Console.ReadKey();
// タスクを削除
service.RootFolder.DeleteTask(TaskIdentifier);
Console.WriteLine($"タスク '{TaskIdentifier}' を削除しました。");
}
}
catch (Exception ex)
{
Console.WriteLine($"エラーが発生しました: {ex.Message}");
Console.WriteLine(ex.StackTrace);
}
finally
{
Console.WriteLine("アプリケーションを終了します。");
}
}
}
TaskSchedulerの応用例と実装のベストプラクティス
応用シナリオ
TaskSchedulerライブラリは、様々なシナリオでその真価を発揮します。
- データ同期: リモートサーバーからのデータ取得や、ローカルデータベース間の定期的なデータ連携。
- システムメンテナンス: 古いログファイルの自動削除、一時ファイルのクリーンアップ、キャッシュの更新。
- レポート生成と配信: 毎日、週次、月次で自動的にビジネスレポートを生成し、関係者へメールで送信。
- バックアップ処理: 定期的なファイルのバックアップや、データベースのスナップショット作成。
実装のベストプラクティス
TaskSchedulerを使用する際の効率的かつ堅牢な実装のためのベストプラクティスを以下に示します。
- タスクの独立性: 異なる目的を持つタスクは、それぞれ独立したタスクとして定義し、互いに影響を与えないように設計します。これにより、コードの可読性と保守性が向上します。
- エラーハンドリングの徹底: タスクの実行中に予期せぬエラーが発生した場合に備え、適切な例外処理とロギングメカニズムを組み込みます。これにより、タスクの失敗がシステム全体に及ぼす影響を最小限に抑え、問題の診断を容易にします。
- リソース管理の最適化: タスクの実行頻度と必要なリソースを考慮し、システムへの負荷が最小限になるようにスケジューリング戦略を調整します。例えば、リソースを大量に消費するタスクは、システムの負荷が低い時間帯に実行するなどの工夫が有効です。
- セキュリティへの配慮: タスクの実行権限を必要最小限に設定し、機密性の高い情報へのアクセスは厳重に管理します。特に、管理者権限を必要とするタスクの場合、その必要性を慎重に検討し、適切なユーザーアカウントで実行するように構成します。
関連する.NETエコシステムプロジェクト
TaskSchedulerライブラリは、単独で使用するだけでなく、他の強力な.NETエコシステムプロジェクトと組み合わせることで、さらに高度な機能を実現できます。
- Entity Framework (EF Core): タスク内でデータベース操作を行う際、EF Coreを組み合わせることで、ORM(Object-Relational Mapping)を通じてオブジェクト指向的にデータを扱うことができます。
- Hangfire: より複雑なバックグラウンドジョブ処理やリトライメカニズムが必要な場合、TaskSchedulerでシステムタスクとしてHangfireのホスティングプロセスを起動し、その中で様々な種類のジョブを管理するという連携も考えられます。
- Quartz.NET: 複雑なクローン式スケジューリングや分散環境でのジョブ実行が必要な場合は、Quartz.NETのような成熟したジョブスケジューリングフレームワークとTaskSchedulerを併用し、それぞれの強みを活かすことができます。例えば、Quartz.NETのスケジューラ自体をTaskSchedulerで起動・管理するといった利用法です。