a.pof
a.pof

Reputation: 53

Azure function app powershell triggers twice/thrice

I got an Azure Alert with an action group that includes my Azure Function App.
The function app is on a consumption plan
However when 1 alert is fired I get two and sometimes three function app replies. Currently testing with email, but can be Teams/Slack/Twilio or something else

I've looked over my code several times but cannot find why it's running several times.
Could this be a cold start issue?
I shouldn't hit the timeout since it finishes in a few seconds
Do I need the following code block?

Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
    StatusCode = $status
})

For example the alert triggered 11/14/2019, 4:59:02 AM
The function app produced three replies:

using namespace System.Net
using namespace System.Web

# Input bindings are passed in via param block.
param($Request) 
# Write to the Azure Functions log stream.
$alert = $Request.RawBody | convertfrom-json

function New-TypeTable([object[]]$columns)
{
    $hash = [ordered]@{}
    foreach ($c in $columns)
    {
        switch ($c.type)
        {
            "datetime" { $type = [datetime] }
            "real" { $type = [decimal] }
            default { $type = [string] }
        }
        $hash.Add($c.name, $type)
    }
    $hash
}

function Set-Culture([System.Globalization.CultureInfo] $culture)
{
    [System.Threading.Thread]::CurrentThread.CurrentUICulture = $culture
    [System.Threading.Thread]::CurrentThread.CurrentCulture = $culture
}

#Set locale to swedish for datetime
Set-Culture sv-SE
#Set variables for later use
$alertRule = $alert.data.essentials.alertRule
$alertDescription = $alert.data.essentials.description
$tables = $alert.data.alertContext.SearchResults.tables

foreach ($table in $tables)
{
    $cHash = New-TypeTable -columns $table.columns
    [string[]]$keys = $cHash.Keys
    $tableInfo = foreach ($row in $table.rows)
    {
        $psObj = New-Object PSObject
        for ($i = 0; $i -lt $row.Count; $i++)
        {
            $value = $row[$i]
            $type = $cHash[$i]
            #Round the value of AggregatedValue and CounterValue
            if ($keys[$i] -eq "AggregatedValue" -Or $keys[$i] -eq "CounterValue") {
                $value = [math]::Round($value,1)
            }
            #Set the value of TimeGenerated to a specific format
            if ($keys[$i] -eq "TimeGenerated") {
                $value = "{0:yyyy-MM-dd HH:mm:ss}" -f $value
            }
            #Don't add Null values
            if($value) {
                $psObj | Add-Member -MemberType NoteProperty -Name $keys[$i] -Value ($value -as $type)
            }
        }
        $psObj
    }
}
#Write-Information $tableInfo -verbose
$Header = @"
<style>
TABLE {width: 750px; border-width: 1px; border-style: solid; border-color: black; border-collapse: collapse;}
TH {border-width: 1px; padding: 3px; border-style: solid; border-color: black; background-color: #6495ED;}
TD {border-width: 1px; padding: 3px; border-style: solid; border-color: black;}
</style>
"@
#Create HTML-table from the object
$Body = $tableInfo | ConvertTo-Html -head $Header

I've added RunOnStartup = false to the function and no difference. Seems like it gets triggered three times by the alert. But the alert only fires once.

DATE (UTC) SUCCESS RESULT CODE DURATION (MS) 
2019-11-18 20:31:16.092 204 799.4648 
2019-11-18 20:29:32.032 204 23197.282 
2019-11-18 20:29:17.956 204 41919.4075

Upvotes: 1

Views: 698

Answers (1)

a.pof
a.pof

Reputation: 53

Okay here's an update after a long case with Azure Support. If anyone that ends up here.

Azure Alert action group using an Azure App Function is at its core an webhook call. This means that it's has the same restrictions/constrains as a regular webhook. See Microsoft docs

After 10 seconds it retries and after another 100 seconds it retries again. If you use an Azure app function on consumption it might take longer for the app function to cold start. This means it can be called up to three times because the app function will run each time it's called even if it takes time to cold start the function (sometimes it starts quicker and you only get two runs and if it's already running you get one run).

Depending on what you're doing this might be a problem. Suggestion by Azure Support in bold and the other are my possible solutions (do note that my suggestions will incur costs)

  • Make the function idempotent
  • Make the function stateful
  • Use an app service plan with always on
  • Use an Logic App
  • If Powershell use an Automation Account runbook

Upvotes: 3

Related Questions