一次在本地运行计时器触发的Azure函数的最简单方法是什么?


75

我有一些使用计时器触发器按计划运行的C#Azure函数。我已经像这样设置了它们,其中%TimerSchedule%在应用程序设置中引用cron表达式:

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

在开发过程中,我经常想使用适用于Visual Studio的Azure函数工具+ Azure Functions核心工具在本地运行函数。但是当我按F5键在本地调试功能时(通常)它不会立即运行。相反,它将根据计时器计划开始等待下一次发生。因此,例如,如果我的cron表达式说每天晚上8点运行,那么我必须等到晚上8点才能使该功能真正在我的机器上运行。

所以我的问题是:使函数在本地运行一次的最简单,最佳方法什么?

我尝试过或考虑过的事情:

  1. 使用更频繁的计时器计划以进行本地开发
    • 可以,但并不完美–除非它非常频繁,否则您还需要稍等一下,如果它非常频繁,则该函数可能会运行多次。这就是我现在正在做的。
  2. 编写直接调用该函数的控制台应用程序或单元测试 Run()方法
    • 这并不是100%直观的,因为您必须提供TimerInfo并提供TraceWriter参数,Run()而我发现令人惊讶的是很少有文档。

Microsoft的“ Azure函数”页面中的代码测试策略在该主题上不是很有帮助–它仅提及将计时器触发器作为测试其他对象的一种方式触发器类型的。

在理想情况下,我按下F5键,该功能将立即运行一次,就像开发一个“普通” .NET应用程序一样。

Answers:


60

我有同样的问题,并仅在调试时使用DEBUG标志具有RunOnStartup:

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

1
看起来很恐怖,但是嘿,这就是我所需要的,并且有效。
Ciaran Gallagher

1
这就是我最终要做的,是的,这很丑陋,但是它可以用于本地调试!
日产

我不明白这件事有多么丑陋。
Szybki

83

您也许可以使用此处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


我是否正确地认为,每当我部署功能时,它也会在云中运行一次功能?此评论似乎表明是。如果是这样,这是朝着正确方向迈出的一大步,但不幸的是,如果我不想更改“生产”行为,则必须在部署之前将其还原。
ripley_

3
@ripley_是的,我相信你是正确的。一种选择是将布尔值绑定到配置中的变量中,类似于如何绑定“ TimerSchedule”。从那里开始,您可以将本地开发设置为true,并将生产(或其他)环境设置为false。
华园

2
如何将RunOnStartup绑定到配置中定义的布尔值。“ %%”语法不适用于非字符串值。
user2297037 '18

Microsoft文档看来,在大多数情况下,建议不要使用RunOnStartup参数。 If true, the function is invoked when the runtime starts. For example, the runtime starts when the function app wakes up after going idle due to inactivity. when the function app restarts due to function changes, and when the function app scales out. **So runOnStartup should rarely if ever be set to true, especially in production**
日产

@日产,这是真的,但是,OP指出这是在本地运行,而不是在生产环境中运行……
华元

38

来自https://docs.microsoft.com/zh-cn/azure/azure-functions/functions-run-local?tabs=windows%2Ccsharp%2Cbash#non-http-triggered-functions

非HTTP触发功能

对于HTTP触发器和Webhooks以外的所有其他功能,您可以通过调用管理端点在本地测试您的功能。在本地服务器上使用HTTP POST请求调用此端点将触发该功能。您可以选择将测试数据传递到POST请求正文中的执行中。此功能类似于Azure门户中的“测试”选项卡。

您调用以下管理员端点来触发非HTTP功能:

http://localhost:{port}/admin/functions/{function_name}

要将测试数据传递给功能的管理员端点,必须在POST请求消息的正文中提供数据。消息正文必须具有以下JSON格式:

{
    "input": "<trigger_input>"
}

2
这应该是公认的答案!在启动时运行很危险,可能会花很多钱!
Michiel Cornille

请注意,默认端口是:7071
Pan Wolodyjowsky '20

9

如果使用的是VS Code,请使用Azure Functions扩展

  1. 按F5键进入调试模式,这将启动功能应用程序。
  2. 转到活动栏中的Azure图标。
  3. 在下Local Project,找到要运行的功能,右键单击,然后选择“立即执行功能”。

查看此MS快速入门指南


1
不知道为什么花这么长时间才找到这个。如果您使用的是VScode,这是最简单的方法,这就是说实话,如果您正在构建Azure Functions,那么这是最简单的方法。谢谢!
Trevor Bye

5

我有同样的问题。我用单元测试修复了它。确实,您需要对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;
}

3

使用邮递员应该可以解决问题。请按照以下步骤在本地运行或调试计时器触发器。

1。运行您的项目。

  1. 打开邮递员并通过此网址 http://localhost:{port}/admin/functions/{function_name}

  2. 确保使用Json正文为{“ input”:“”}的POST方法

  3. 按发送。

您应该收到202的回复。


0

只需在同一类中添加具有HTTP触发器类型的另一个函数,添加代码或从该函数调用Run方法并从浏览器中调用它即可。

在部署到产品中时,请确保注释/删除该功能,否则您将能够通过产品中的HTTP调用来触发该功能。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.