Каков самый простой способ запуска функции 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.