Was ist der einfachste Weg, um eine durch einen Timer ausgelöste Azure-Funktion einmal lokal auszuführen?

75

Ich habe einige C # Azure-Funktionen, die nach einem Zeitplan mit Timer-Triggern ausgeführt werden . Ich habe sie so eingerichtet, wobei %TimerSchedule%auf einen Cron-Ausdruck in den App-Einstellungen verwiesen wird:

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

Während der Entwicklung möchte ich die Funktionen häufig lokal mit den Azure-Funktionstools für Visual Studio + Azure-Funktionen-Kerntools ausführen. Aber wenn ich F5 drücke, um die Funktion lokal zu debuggen, wird sie (normalerweise) nicht sofort ausgeführt. Stattdessen wird gemäß dem Timer-Zeitplan auf das nächste Auftreten gewartet. Wenn mein Cron-Ausdruck beispielsweise sagt, dass er täglich um 20 Uhr ausgeführt werden soll, muss ich bis 20 Uhr warten, bis die Funktion tatsächlich auf meinem Computer ausgeführt wird.

Meine Frage lautet also: Was ist der einfachste und beste Weg, um eine Funktion einmal lokal auszuführen?

Dinge, die ich versucht oder in Betracht gezogen habe:

  1. Verwenden Sie einen häufigeren Timer-Zeitplan nur für die lokale Entwicklung
    • Dies ist in Ordnung, aber nicht perfekt. Sie müssen immer noch ein wenig warten, es sei denn, es ist sehr häufig. Wenn es sehr häufig ist, wird die Funktion möglicherweise mehrmals ausgeführt. Das mache ich jetzt.
  2. Schreiben Sie eine Konsolen-App oder einen Komponententest, der die Run()Methode der Funktion direkt aufruft
    • Dies ist nicht zu 100% einfach , weil Sie zu bieten haben TimerInfound TraceWriterArgumente zu Run()- und ich habe überraschend wenig Dokumentation dafür gefunden.

Die Strategien von Microsoft zum Testen Ihres Codes auf der Seite " Azure-Funktionen " sind in diesem Thema nicht sehr hilfreich. Sie erwähnen nur Timer-Trigger, um andere Triggertypen zu testen .

In einer perfekten Welt würde ich F5 drücken und die Funktion würde sofort einmal ausgeführt - genau wie bei der Entwicklung einer "normalen" .NET-App.

ripley_
quelle

Antworten:

59

Ich hatte die gleiche Frage und benutzte das DEBUG-Flag, um RunOnStartup nur während des Debuggens zu haben:

        public static void Run(
            [TimerTrigger("* 0 7 * * 1-5"
#if DEBUG
            , RunOnStartup=true
#endif
            )]TimerInfo myTimer, TraceWriter log)
        {
BerDev
quelle
1
Es sieht schrecklich aus, aber hey, das ist was ich brauche und es funktioniert.
Ciaran Gallagher
1
Dies ist, was ich letztendlich getan habe, und ja, es ist hässlich, aber es funktioniert für lokale Debugging-Zwecke!
Nissan
Ich verstehe nicht, was daran so hässlich ist.
Szybki
83

Sie könnten vielleicht die hierRunOnStartup dokumentierte Flagge verwenden . Es entspricht nicht ganz Ihrem Auftrag, es nur einmal auszuführen, sollte es jedoch zumindest lokal ausführen, sobald die App gestartet wurde.

/// 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.

Beispiel mit Attributbindung:

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

Wah Yuen
quelle
Bin ich zu Recht der Meinung, dass dies die Funktion auch einmal in der Cloud ausführen würde, wenn ich die Funktion bereitstelle? Dieser Kommentar scheint ja zu sein. Wenn ja, ist dies ein großer Schritt in die richtige Richtung, aber es ist ein wenig bedauerlich, dass er vor der Bereitstellung zurückgesetzt werden muss, wenn ich das "Produktions" -Verhalten nicht ändern möchte.
ripley_
3
@ipley_ ja, ich glaube du würdest richtig liegen. Eine Option könnte sein, dass Sie den Booleschen Wert in eine Variable in Ihrer Konfiguration einbinden, ähnlich wie Sie Ihre 'TimerSchedule' gebunden haben. Von dort aus können Sie Ihre lokale Entwicklung auf true und Ihre Produktionsumgebungen (oder andere Umgebungen) auf false setzen, wie Sie es für richtig halten.
Wah Yuen
2
Wie kann ich RunOnStartup an einen in meiner Konfiguration definierten Booleschen Wert binden? Die Syntax "%%" funktioniert nicht für Werte ohne Zeichenfolge.
user2297037
Aus der Microsoft-Dokumentation geht hervor, dass in den meisten Fällen die Verwendung des RunOnStartup-Parameters empfohlen wird. 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**
Nissan
@ Nissan dies ist wahr, aber das OP gab an, dass dies für die lokale Ausführung und nicht in einer Produktionsumgebung war ...
Wah Yuen
38

Von https://docs.microsoft.com/en-us/azure/azure-functions/functions-run-local?tabs=windows%2Ccsharp%2Cbash#non-http-triggered-functions

Nicht HTTP-ausgelöste Funktionen

Für alle Arten von Funktionen außer HTTP-Triggern und Webhooks können Sie Ihre Funktionen lokal testen, indem Sie einen Administrationsendpunkt aufrufen. Das Aufrufen dieses Endpunkts mit einer HTTP-POST-Anforderung auf dem lokalen Server löst die Funktion aus. Optional können Sie Testdaten an die Ausführung im Hauptteil der POST-Anforderung übergeben. Diese Funktionalität ähnelt der Registerkarte Test im Azure-Portal.

Sie rufen den folgenden Administratorendpunkt auf, um Nicht-HTTP-Funktionen auszulösen:

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

Um Testdaten an den Administratorendpunkt einer Funktion zu übergeben, müssen Sie die Daten im Hauptteil einer POST-Anforderungsnachricht angeben. Der Nachrichtentext muss das folgende JSON-Format haben:

{
    "input": "<trigger_input>"
}
Nissan
quelle
2
Dies sollte die akzeptierte Antwort sein! Run On Startup ist gefährlich und kann viel Geld kosten!
Michiel Cornille
Nur als Hinweis, Standardport ist: 7071
Pan Wolodyjowsky
9

Wenn Sie VS-Code verwenden, verwenden Sie die Erweiterung Azure-Funktionen :

  1. Drücken Sie F5, um den Debug-Modus aufzurufen. Dadurch wird die Funktions-App gestartet.
  2. Wechseln Sie in der Aktivitätsleiste zum Azure-Symbol.
  3. Unter Local Projectfinden Sie die Funktion , die Sie ausführen möchten, die rechte Maustaste und wählen Sie „Jetzt ausführen Function“.

Lesen Sie diese MS- Kurzanleitung .

Renel Chesak
quelle
1
Keine Ahnung, warum es so lange gedauert hat, dies zu finden. Dies ist bei weitem der einfachste Weg, wenn Sie VScode verwenden. Um ehrlich zu sein, sind Sie dies wahrscheinlich, wenn Sie Azure-Funktionen erstellen. Dankeschön!
Trevor Bye
5

Ich hatte die gleiche Frage. Ich habe es mit einem Unittest behoben. In der Tat müssen Sie den TraceWriter und die TimerInfo auslöschen.

Hier ein Code, wie ich das gemacht habe.

TimerInfo:

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

Und der 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;
}
StefanHa
quelle
3

Die Verwendung eines Postboten sollte den Trick tun. Führen Sie die folgenden Schritte aus, um den Timer-Trigger lokal auszuführen oder zu debuggen.

1. Führen Sie Ihr Projekt aus.

  1. Öffnen Sie Postman und hinter dieser URL http://localhost:{port}/admin/functions/{function_name}

  2. Stellen Sie sicher, dass Sie eine POST-Methode mit dem Json-Body von {"input": ""} verwenden.

  3. Drücken Sie SENDEN.

Sie sollten eine Antwort von 202 erhalten.

maxspan
quelle
0

Fügen Sie einfach eine weitere Funktion mit HTTP-Triggertyp innerhalb derselben Klasse hinzu, fügen Sie Ihren Code hinzu oder rufen Sie Ihre Run-Methode über diese Funktion auf und rufen Sie sie über Ihren Browser auf.

Stellen Sie sicher, dass Sie diese Funktion kommentieren / entfernen, wenn Sie für prod bereitgestellt werden. Andernfalls können Sie die Funktion über HTTP-Aufrufe in prod auslösen.

Mike Cardona
quelle