Aracılığıyla paylaş


Dayanıklı İşlevler'de senaryoyu izleme - Hava durumu izleyicisi örneği

İzleyici deseni, bir iş akışındaki esnek yinelenen işlemi ifade eder; örneğin, belirli koşullar karşılanana kadar yoklama. Bu makalede, izlemeyi uygulamak için Dayanıklı İşlevler kullanan bir örnek açıklanmaktadır.

Önkoşullar

Senaryoya genel bakış

Bu örnek bir konumun geçerli hava koşullarını izler ve gökyüzü temiz olduğunda kullanıcıyı SMS ile uyarır. Hava durumunu denetlemek ve uyarılar göndermek için düzenli bir zamanlayıcı ile tetiklenen işlev kullanabilirsiniz. Ancak, bu yaklaşımla ilgili bir sorun yaşam süresi yönetimidir. Yalnızca bir uyarı gönderilmesi gerekiyorsa, temiz hava algılandıktan sonra izleyicinin kendini devre dışı bırakması gerekir. İzleme düzeni, diğer avantajların dışında kendi yürütmesini sonlandırabilir:

  • İzleyiciler zamanlamaya göre değil aralıklarla çalışır: zamanlayıcı tetikleyicisi saatte bir çalışır ; bir izleyici eylemler arasında bir saat bekler. Bir izleyicinin eylemleri belirtilmedikçe çakışmaz ve bu durum uzun süre çalışan görevler için önemli olabilir.
  • İzleyicilerin dinamik aralıkları olabilir: Bekleme süresi bazı koşullar temelinde değişebilir.
  • Bazı koşullar karşılandığında veya başka bir işlem tarafından sonlandırıldığında izleyiciler sonlandırılabilir.
  • İzleyiciler parametre alabilir. Örnek, aynı hava durumu izleme işleminin istenen herhangi bir konuma ve telefon numarasına nasıl uygulanabileceğini gösterir.
  • İzleyiciler ölçeklenebilir. Her izleyici bir düzenleme örneği olduğundan, yeni işlevler oluşturmak veya daha fazla kod tanımlamak zorunda kalmadan birden çok monitör oluşturulabilir.
  • İzleyiciler daha büyük iş akışlarıyla kolayca tümleştirilir. İzleyici, daha karmaşık bir düzenleme işlevinin bir bölümü veya alt düzenleme olabilir.

Yapılandırma

Twilio tümleştirmesini yapılandırma

Bu örnek, cep telefonuna SMS mesajları göndermek için Twilio hizmetini kullanmayı içerir. Azure İşlevleri zaten Twilio bağlaması aracılığıyla Twilio desteğine sahiptir ve örnek bu özelliği kullanır.

İhtiyacınız olan ilk şey bir Twilio hesabıdır. adresinde https://www.twilio.com/try-twilioücretsiz bir tane oluşturabilirsiniz. Bir hesabınız olduğunda aşağıdaki üç uygulama ayarlarını işlev uygulamanıza ekleyin.

Uygulama ayarı adı Değer açıklaması
TwilioAccountSid Twilio hesabınızın SID değeri
TwilioAuthToken Twilio hesabınız için kimlik doğrulama belirteci
TwilioPhoneNumber Twilio hesabınızla ilişkili telefon numarası. Bu, SMS mesajları göndermek için kullanılır.

Weather Underground tümleştirmesini yapılandırma

Bu örnek, bir konumun geçerli hava koşullarını denetlemek için Weather Underground API'sini kullanmayı içerir.

İhtiyacınız olan ilk şey weather underground hesabı. adresinde ücretsiz https://www.wunderground.com/signupolarak oluşturabilirsiniz. Bir hesabınız olduğunda bir API anahtarı almanız gerekir. Bunu yapmak için adresini ziyaret https://www.wunderground.com/weather/apiedebilir ve ardından Anahtar Ayarları'nı seçebilirsiniz. Stratus Geliştirici planı ücretsizdir ve bu örneği çalıştırmak için yeterlidir.

API anahtarınız olduktan sonra aşağıdaki uygulama ayarını işlev uygulamanıza ekleyin.

Uygulama ayarı adı Değer açıklaması
WeatherUndergroundApiKey Weather Underground API anahtarınız.

İşlevler

Bu makalede, örnek uygulamada aşağıdaki işlevler açıklanmaktadır:

  • E3_Monitor: Düzenli aralıklarla çağıran E3_GetIsClearbir düzenleyici işlevi. True döndürürse E3_GetIsClear çağırırE3_SendGoodWeatherAlert.
  • E3_GetIsClear: Bir konum için geçerli hava koşullarını denetleen bir etkinlik işlevi .
  • E3_SendGoodWeatherAlert: Twilio aracılığıyla SMS mesajı gönderen bir etkinlik işlevi.

E3_Monitor orchestrator işlevi

[FunctionName("E3_Monitor")]
public static async Task Run([OrchestrationTrigger] IDurableOrchestrationContext monitorContext, ILogger log)
{
    MonitorRequest input = monitorContext.GetInput<MonitorRequest>();
    if (!monitorContext.IsReplaying) { log.LogInformation($"Received monitor request. Location: {input?.Location}. Phone: {input?.Phone}."); }

    VerifyRequest(input);

    DateTime endTime = monitorContext.CurrentUtcDateTime.AddHours(6);
    if (!monitorContext.IsReplaying) { log.LogInformation($"Instantiating monitor for {input.Location}. Expires: {endTime}."); }

    while (monitorContext.CurrentUtcDateTime < endTime)
    {
        // Check the weather
        if (!monitorContext.IsReplaying) { log.LogInformation($"Checking current weather conditions for {input.Location} at {monitorContext.CurrentUtcDateTime}."); }

        bool isClear = await monitorContext.CallActivityAsync<bool>("E3_GetIsClear", input.Location);

        if (isClear)
        {
            // It's not raining! Or snowing. Or misting. Tell our user to take advantage of it.
            if (!monitorContext.IsReplaying) { log.LogInformation($"Detected clear weather for {input.Location}. Notifying {input.Phone}."); }

            await monitorContext.CallActivityAsync("E3_SendGoodWeatherAlert", input.Phone);
            break;
        }
        else
        {
            // Wait for the next checkpoint
            var nextCheckpoint = monitorContext.CurrentUtcDateTime.AddMinutes(30);
            if (!monitorContext.IsReplaying) { log.LogInformation($"Next check for {input.Location} at {nextCheckpoint}."); }

            await monitorContext.CreateTimer(nextCheckpoint, CancellationToken.None);
        }
    }

    log.LogInformation($"Monitor expiring.");
}

[Deterministic]
private static void VerifyRequest(MonitorRequest request)
{
    if (request == null)
    {
        throw new ArgumentNullException(nameof(request), "An input object is required.");
    }

    if (request.Location == null)
    {
        throw new ArgumentNullException(nameof(request.Location), "A location input is required.");
    }

    if (string.IsNullOrEmpty(request.Phone))
    {
        throw new ArgumentNullException(nameof(request.Phone), "A phone number input is required.");
    }
}

Düzenleyici, izlenecek bir konum ve konumda netleşip netleşmeyeceği konusunda ileti göndermek için bir telefon numarası gerektirir. Bu veriler düzenleyiciye kesin olarak yazılan bir nesne olarak geçirilir MonitorRequest .

Bu düzenleyici işlevi aşağıdaki eylemleri gerçekleştirir:

  1. İzlenecek konumdan ve SMS bildirimi göndereceği telefon numarasından oluşan MonitorRequest'i alır.
  2. İzleyicinin süre sonunu belirler. Örnek, kısaltma için sabit kodlanmış bir değer kullanır.
  3. İstenen konumda açık gökyüzü olup olmadığını belirlemek için E3_GetIsClear çağırır.
  4. Hava açıksa, istenen telefon numarasına SMS bildirimi göndermek için E3_SendGoodWeatherAlert arar.
  5. Sonraki yoklama aralığında düzenlemeyi sürdürmek için dayanıklı bir zamanlayıcı oluşturur. Örnek, kısaltma için sabit kodlanmış bir değer kullanır.
  6. Geçerli UTC saati izleyicinin son kullanma saatini geçene veya sms uyarısı gönderilene kadar çalışmaya devam eder.

Birden çok düzenleyici örneği, orchestrator işlevini birden çok kez çağırarak aynı anda çalıştırılabilir. İzlenecek konum ve SMS uyarısı gönderilecek telefon numarası belirtilebilir. Son olarak, zamanlayıcıyı beklerken orchestrator işlevinin çalışmadığını , dolayısıyla bunun için ücretlendirilmeyeceğini unutmayın.

E3_GetIsClear etkinlik işlevi

Diğer örneklerde olduğu gibi yardımcı etkinlik işlevleri de tetikleyici bağlamasını activityTrigger kullanan normal işlevlerdir. E3_GetIsClear işlevi Weather Underground API'sini kullanarak geçerli hava koşullarını alır ve gökyüzünün temiz olup olmadığını belirler.

[FunctionName("E3_GetIsClear")]
public static async Task<bool> GetIsClear([ActivityTrigger] Location location)
{
    var currentConditions = await WeatherUnderground.GetCurrentConditionsAsync(location);
    return currentConditions.Equals(WeatherCondition.Clear);
}

E3_SendGoodWeatherAlert etkinlik işlevi

E3_SendGoodWeatherAlert işlevi, son kullanıcıya yürüyüş için uygun bir zaman olduğunu bildiren bir SMS iletisi göndermek için Twilio bağlamasını kullanır.

    [FunctionName("E3_SendGoodWeatherAlert")]
    public static void SendGoodWeatherAlert(
        [ActivityTrigger] string phoneNumber,
        ILogger log,
        [TwilioSms(AccountSidSetting = "TwilioAccountSid", AuthTokenSetting = "TwilioAuthToken", From = "%TwilioPhoneNumber%")]
            out CreateMessageOptions message)
    {
        message = new CreateMessageOptions(new PhoneNumber(phoneNumber));
        message.Body = $"The weather's clear outside! Go take a walk!";
    }

internal class WeatherUnderground
{
    private static readonly HttpClient httpClient = new HttpClient();
    private static IReadOnlyDictionary<string, WeatherCondition> weatherMapping = new Dictionary<string, WeatherCondition>()
    {
        { "Clear", WeatherCondition.Clear },
        { "Overcast", WeatherCondition.Clear },
        { "Cloudy", WeatherCondition.Clear },
        { "Clouds", WeatherCondition.Clear },
        { "Drizzle", WeatherCondition.Precipitation },
        { "Hail", WeatherCondition.Precipitation },
        { "Ice", WeatherCondition.Precipitation },
        { "Mist", WeatherCondition.Precipitation },
        { "Precipitation", WeatherCondition.Precipitation },
        { "Rain", WeatherCondition.Precipitation },
        { "Showers", WeatherCondition.Precipitation },
        { "Snow", WeatherCondition.Precipitation },
        { "Spray", WeatherCondition.Precipitation },
        { "Squall", WeatherCondition.Precipitation },
        { "Thunderstorm", WeatherCondition.Precipitation },
    };

    internal static async Task<WeatherCondition> GetCurrentConditionsAsync(Location location)
    {
        var apiKey = Environment.GetEnvironmentVariable("WeatherUndergroundApiKey");
        if (string.IsNullOrEmpty(apiKey))
        {
            throw new InvalidOperationException("The WeatherUndergroundApiKey environment variable was not set.");
        }

        var callString = string.Format("http://api.wunderground.com/api/{0}/conditions/q/{1}/{2}.json", apiKey, location.State, location.City);
        var response = await httpClient.GetAsync(callString);
        var conditions = await response.Content.ReadAsAsync<JObject>();

        JToken currentObservation;
        if (!conditions.TryGetValue("current_observation", out currentObservation))
        {
            JToken error = conditions.SelectToken("response.error");

            if (error != null)
            {
                throw new InvalidOperationException($"API returned an error: {error}.");
            }
            else
            {
                throw new ArgumentException("Could not find weather for this location. Try being more specific.");
            }
        }

        return MapToWeatherCondition((string)(currentObservation as JObject).GetValue("weather"));
    }

    private static WeatherCondition MapToWeatherCondition(string weather)
    {
        foreach (var pair in weatherMapping)
        {
            if (weather.Contains(pair.Key))
            {
                return pair.Value;
            }
        }

        return WeatherCondition.Other;
    }
}

Not

Örnek kodu çalıştırmak için Nuget paketini yüklemeniz Microsoft.Azure.WebJobs.Extensions.Twilio gerekir.

Örneği çalıştırma

Örnekteki HTTP ile tetiklenen işlevleri kullanarak, aşağıdaki HTTP POST isteğini göndererek düzenlemeyi başlatabilirsiniz:

POST https://{host}/orchestrators/E3_Monitor
Content-Length: 77
Content-Type: application/json

{ "location": { "city": "Redmond", "state": "WA" }, "phone": "+1425XXXXXXX" }
HTTP/1.1 202 Accepted
Content-Type: application/json; charset=utf-8
Location: https://{host}/runtime/webhooks/durabletask/instances/f6893f25acf64df2ab53a35c09d52635?taskHub=SampleHubVS&connection=Storage&code={SystemKey}
RetryAfter: 10

{"id": "f6893f25acf64df2ab53a35c09d52635", "statusQueryGetUri": "https://{host}/runtime/webhooks/durabletask/instances/f6893f25acf64df2ab53a35c09d52635?taskHub=SampleHubVS&connection=Storage&code={systemKey}", "sendEventPostUri": "https://{host}/runtime/webhooks/durabletask/instances/f6893f25acf64df2ab53a35c09d52635/raiseEvent/{eventName}?taskHub=SampleHubVS&connection=Storage&code={systemKey}", "terminatePostUri": "https://{host}/runtime/webhooks/durabletask/instances/f6893f25acf64df2ab53a35c09d52635/terminate?reason={text}&taskHub=SampleHubVS&connection=Storage&code={systemKey}"}

E3_Monitor örneği başlatılır ve istenen konum için geçerli hava koşullarını sorgular. Hava açıksa uyarı göndermek için bir etkinlik işlevi çağırır; aksi takdirde, bir süreölçer ayarlar. Süreölçerin süresi dolduğunda düzenleme devam eder.

Azure İşlevleri portalındaki işlev günlüklerine bakarak düzenlemenin etkinliğini görebilirsiniz.

2018-03-01T01:14:41.649 Function started (Id=2d5fcadf-275b-4226-a174-f9f943c90cd1)
2018-03-01T01:14:42.741 Started orchestration with ID = '1608200bb2ce4b7face5fc3b8e674f2e'.
2018-03-01T01:14:42.780 Function completed (Success, Id=2d5fcadf-275b-4226-a174-f9f943c90cd1, Duration=1111ms)
2018-03-01T01:14:52.765 Function started (Id=b1b7eb4a-96d3-4f11-a0ff-893e08dd4cfb)
2018-03-01T01:14:52.890 Received monitor request. Location: Redmond, WA. Phone: +1425XXXXXXX.
2018-03-01T01:14:52.895 Instantiating monitor for Redmond, WA. Expires: 3/1/2018 7:14:52 AM.
2018-03-01T01:14:52.909 Checking current weather conditions for Redmond, WA at 3/1/2018 1:14:52 AM.
2018-03-01T01:14:52.954 Function completed (Success, Id=b1b7eb4a-96d3-4f11-a0ff-893e08dd4cfb, Duration=189ms)
2018-03-01T01:14:53.226 Function started (Id=80a4cb26-c4be-46ba-85c8-ea0c6d07d859)
2018-03-01T01:14:53.808 Function completed (Success, Id=80a4cb26-c4be-46ba-85c8-ea0c6d07d859, Duration=582ms)
2018-03-01T01:14:53.967 Function started (Id=561d0c78-ee6e-46cb-b6db-39ef639c9a2c)
2018-03-01T01:14:53.996 Next check for Redmond, WA at 3/1/2018 1:44:53 AM.
2018-03-01T01:14:54.030 Function completed (Success, Id=561d0c78-ee6e-46cb-b6db-39ef639c9a2c, Duration=62ms)

Düzenleme, zaman aşımına ulaşıldığında veya açık gökyüzü algılandığında tamamlanır. API'yi terminate başka bir işlev içinde de kullanabilir veya yukarıdaki 202 yanıtında başvurulan terminatePostUri HTTP POST web kancasını çağırabilirsiniz. Web kancasını kullanmak için değerini erken sonlandırma nedeni ile değiştirin {text} . HTTP POST URL'si kabaca aşağıdaki gibi görünür:

POST https://{host}/runtime/webhooks/durabletask/instances/f6893f25acf64df2ab53a35c09d52635/terminate?reason=Because&taskHub=SampleHubVS&connection=Storage&code={systemKey}

Sonraki adımlar

Bu örnek, dayanıklı zamanlayıcılar ve koşullu mantık kullanarak dış kaynağın durumunu izlemek için Dayanıklı İşlevler nasıl kullanılacağını göstermiştir. Sonraki örnekte, insan etkileşimini işlemek için dış olayların ve dayanıklı zamanlayıcıların nasıl kullanılacağı gösterilmektedir.