C#の信頼性の高い遅延/スケジュールされた実行のベストプラクティス
-
22-08-2019 - |
質問
私が取り組んでいるプロジェクトでは、特定の時間にいくつかの実行を行う必要があります。この状況に対処する最善の方法は何なのかわかりません。メソッドはサーバーの再起動/メンテナンス後も存続できる必要があります。また、メソッド呼び出しはプログラム的に行う必要があります。
私はこの道に進むことを検討しています:
データベース(またはメッセージキュー)にTaskTableと呼ばれるテーブルを作成できます。このテーブルには、TaskID(PK)、TaskName(varchar)、TaskStatus(enum success、failed、scheduled)、およびTimeOfExecutionを含めることができます。ただし、未実行のタスクがないかデータベースを定期的にポーリングする Windows サービスが必要です。私が直面している問題は次のとおりです:データベースに保存するタスク名として何を使用すればよいですか?クラス名?クラス名とメソッド名はToString?また、文字列を変換してプログラムでメソッド呼び出しを呼び出すにはどうすればよいでしょうか (巨大な switch ステートメントは使いたくないのですが)。典型的なタスクは以下のようになります。したがって、タスク「SendIncompleteNotification」の名前とクラス名を取得してデータベースに保存し、取得時にプログラムで呼び出すことができる必要がありました。
public static Task<string> SendIncompleteNotification
{
get
{
return new Task<string>
(
a => Console.WriteLine("Sample Task")
, "This is a sample task which does nothing."
);
}
}
現在の問題は、メソッド/プロパティ名をプログラム的に保存するときに問題が発生していることです。
var type = ApplicationTask.SendIncompleteNotification.GetType();
//type.Name shows "Task`1" rather than SendIncompleteNotification
この状況に対処するより良い方法はありますか?ありがとう!
更新しました:ごめんなさい、頭が回転していました。今、私が間違っていたのは、タスクを返す別のメソッド/プロパティがあったことだと気づきました。私がすべきだったのは、タスクから新しいクラスを継承させることでした。そして、そこで簡単にクラス名を取得し、文字列をデータベースに保存し、後でリタイアして元に戻して呼び出すことができます。
解決
データベースは必須ですか?
そうでない場合は、一般的なコンソール アプリを呼び出す Windows スケジュール タスク (「ただ動作する」傾向がある) はどうでしょうか。コンソール アプリへの引数は次のとおりです。
- 実行するタスクを含むDLL
- 定義したインターフェースを実装するクラスの名前
- その他の引数
このようにして、すべてのタスクを 1 つまたは複数のアセンブリに入れることができます。あるいは、属性を作成し、その属性をタスクに適用してタスクに「わかりやすい名前」を付け、アセンブリのリフレクションを使用して一致する属性を持つクラスを見つけることもできます。
編集:例:
interface ITask
{
void Execute(ExcecutionContext context);
}
[TaskName("Send Emails")
class SendEmailsTask : ITask
{
public void Execute(ExcecutionContext context)
{
// Send emails. ExecutionContext might contain a dictionary of
// key/value pairs for additional arguments needed for your task.
}
}
class TaskExecuter
{
public void ExecuteTask(string name)
{
// "name" comes from the database entry
var types = Assembly.GetExecutingAssembly().GetTypes();
foreach (var type in types)
{
// Check type.GetCustomAttributes for the TaskAttribute, then check the name
}
}
}
編集2:これはコードサンプルに対する答えです。
class YourClass
{
public static Task<string> SendIncompleteNotification
{
get {
return new Task<string>(
s => Console.WriteLine("Executing task... arguments: {0}", s),
"My task");
}
}
}
interface ITask
{
void Execute(object o);
}
class Task<T> : ITask
{
public Task(Action<T> action, string name)
{
Action = action;
}
public string Name { get; set; }
public Action<T> Action { get; set; }
void ITask.Execute(object o)
{
Action((T)o);
}
}
class Program
{
static void Main(string[] args)
{
// Assume that this is what is stored in the database
var typeName = typeof (YourClass).FullName;
var propertyName = "SendIncompleteNotification";
var arguments = "some arguments";
// Execute the task
var type = Type.GetType(typeName);
var property = type.GetProperty(propertyName);
var task = (ITask)property.GetValue(null, null);
task.Execute(arguments);
Console.ReadKey();
}
}
他のヒント
あなたは、Windowsワークフローに見たいと思うかもしれません。彼らは、長い実行中のプロセスのために設計されている私の知る限りでは、データベースに永続化し、イベントやタイマーでウェイクアップすることができます。
アセンブリのFullNameを保存し、フルネームやメソッド名を入力します。メソッドのシグネチャと仮定すると(パラメータなしのようにして返すのボイド)予測可能なものである。
1)組み立て式の静的LoadFromメソッドを使用してアセンブリのインスタンスを作成します。
2)GetTypeメソッドを使用してアセンブリからクラス型への参照を取得します。
3)GetMethodメソッドを使用して型からMETHODINFOインスタンスを取得
4)Activator.CreateInstanceを使用して型のインスタンスを作成する
5)私は実際のコードをクランクするためにVSのコピーせずに公共のコンピュータでだと申し訳ありませんが、これらの5つのステップ(ステップ4からクラスのインスタンスを渡し、METHODINFOインスタンスの起動を考え使用してメソッドを実行しますやるます。
また、あなたは、SQL 2005はSqlDependencyオブジェクトを使用することを検討して使用していて、「通知」なった場合ときではなく、ポーリング。あなたtalbeの変更
あなたが見てきましたクォーツに、それはかなりうまく機能し、私はそれがすべて実装してかなり確信していますあなたが必要とする機能ます。