Каков самый простой способ запуска функции Azure с таймером локально один раз?

У меня есть несколько функций С# Azure, которые выполняются по расписанию с помощью таймеров триггеров. Я установил их так, где %TimerSchedule% относится к выражению cron в настройках приложения:

public static void Run([TimerTrigger("%TimerSchedule%")]TimerInfo myTimer, TraceWriter log)

Во время разработки я часто хочу запускать функции локально с помощью инструментов Azure для инструментов Visual Studio + Azure Core. Но когда я нажимаю F5 для отладки функции локально, она (обычно) не запускается немедленно. Вместо этого он начинает ждать следующего события в соответствии с расписанием таймера. Так, например, если мое выражение cron говорит, что он будет работать ежедневно в 8 вечера, мне придется подождать до 8 вечера, чтобы функция фактически выполнялась на моей машине.

Итак, мой вопрос: Каков самый простой и лучший способ заставить функцию запускаться локально?

Вещи, которые я пробовал:

  • Используйте более частый график таймера только для локального развития
    • Это нормально, но не идеально - вам все равно придется немного подождать, если это не очень часто, и если это очень часто, функция может выполняться несколько раз. Это то, что я делаю сейчас.
  • Напишите консольное приложение или unit test, которое напрямую вызывает функцию Run()
    • Это не на 100% прямолинейно, потому что вы должны предоставить аргументы TimerInfo и TraceWriter для Run() - и я нашел для этого удивительно небольшую документацию.

Microsoft Стратегии для тестирования вашего кода на странице Azure Functions не очень полезны в этой теме - он упоминает только триггеры таймера как способ тестирования другие типы триггеров.

В идеальном мире я бы ударил F5, и функция сразу же запустилась сразу - так же, как разработать "нормальное" приложение .NET.

Ответ 1

Возможно, вы можете использовать флаг RunOnStartup, как описано здесь. Это не совсем соответствует вашему резюме, поскольку он работает только один раз, но он должен, по крайней мере, выполнить его локально после запуска приложения.

/// Gets or sets a value indicating whether the function should be invoked
/// immediately on startup. After the initial startup run, the function will
/// be run on schedule thereafter.

Пример использования привязки атрибута:

[TimerTrigger("%TimerSchedule%", RunOnStartup = true)]TimerInfo myTimer

Ответ 2

У меня был тот же вопрос, и я использовал флаг DEBUG для запуска RunOnStartup только во время отладки:

        public static void Run(
            [TimerTrigger("* 0 7 * * 1-5"
#if DEBUG
            , RunOnStartup=true
#endif
            )]TimerInfo myTimer, TraceWriter log)
        {

Ответ 3

У меня такой же вопрос. Я исправил это с помощью Unittest. На самом деле вам нужно заглушить TraceWriter и TimerInfo.

Вот некоторый код, как я это сделал.

TimerInfo:

public class ScheduleStub : TimerInfo
{
    public ScheduleStub(TimerSchedule schedule, ScheduleStatus status, bool isPastDue = false) : base(schedule, status, isPastDue)
    {
    }
}

И TraceWriter:

 public class TraceWriterStub : TraceWriter
{
    protected TraceLevel _level;
    protected List<TraceEvent> _traces;

    public TraceWriterStub(TraceLevel level) : base(level)
    {
        _level = level;
        _traces = new List<TraceEvent>();
    }

    public override void Trace(TraceEvent traceEvent)
    {
        _traces.Add(traceEvent);
    }

    public List<TraceEvent> Traces => _traces;
}

Ответ 4

Просто добавьте еще одну функцию с типом триггера HTTP в том же классе, добавьте свой код или вызовите метод Run из этой функции и вызовите его из браузера.

Обязательно прокомментируйте/удалите эту функцию при развертывании в prod, иначе у вас будет возможность вызвать функцию через HTTP-вызовы в prod.