лучшая практика надежного отложенного / запланированного выполнения c #

StackOverflow https://stackoverflow.com/questions/684406

Вопрос

Проект, над которым я работаю, требует выполнения некоторых операций в определенное время.Я не уверен, что было бы лучшим способом справиться с этой ситуацией.Метод должен быть способен выдержать перезапуск / обслуживание сервера.И вызовы методов должны выполняться программно.

Я подумываю о том, чтобы пойти по этому пути:

У меня могла бы быть таблица в базе данных (или даже очередь сообщений) с именем TaskTable, которая могла бы иметь TaskId (PK), TaskName (varchar), TaskStatus (перечисление успешно, сбой, запланировано) и 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, содержащая задачу для выполнения
  • Имя класса, реализующего определенный вами интерфейс
  • Другие аргументы

Таким образом, вы можете поместить все ваши задачи в одну сборку или несколько.В качестве альтернативы вы могли бы создать атрибут, применить этот атрибут к своим задачам, чтобы присвоить им "понятное название", и использовать отражение над сборкой, чтобы найти классы с соответствующим атрибутом.

Редактировать:пример:

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.Они предназначены для длительно выполняющихся процессов, могут сохраняться в базе данных и запускаться по событию или таймеру, насколько я знаю.

Сохраните полное имя сборки и введите полное имя и имя метода.Предполагая, что сигнатура метода является чем-то предсказуемым (например, отсутствие параметров и возврат void)

1) создайте экземпляр сборки, используя статический метод LoadFrom типа Assembly.

2) получите ссылку на тип класса из вашей сборки, используя метод GetType

3) получить экземпляр MethodInfo из типа, используя метод GetMethod

4) создайте экземпляр типа с помощью Activator.CreateInstance

5) выполните метод, используя вызов экземпляра MethodInfo, передавая экземпляр класса с шага 4.(извините, что я нахожусь на общедоступном компьютере без копии VS, чтобы провернуть реальный код, но этих 5 шагов было бы достаточно.

Также, если вы используете SQL 2005, рассмотрите возможность использования объекта SqlDependency и получения "уведомления" при изменении вашего talbe, а не опроса.

Вы смотрели на Кварц, это работает довольно хорошо, и я почти уверен, что в нем реализованы все необходимые вам функции.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top