Azure Functions TimeTrigger never triggers.

Bob Meijwaard 20 Reputation points
2023-03-02T15:51:28.7633333+00:00

Hi
Since my question got deleted for violating something, here is another attempt (without pictures this time)

I have a function app that has multiple triggers, each with different type of triggers. But the timetriggers are not firing. Also I am not able to start triggers from the Azure portal console. The buttons are greyed out and this message is below (Your app is currently in read only mode because you are running from a package file. To make any changes update the content in your zip file and WEBSITE_RUN_FROM_PACKAGE app setting.) WEBSITE_RUN_FROM_PACKAGE is set to 1.

Though the blob and queue triggers fire as per expected.

Are you using Consumption or App Service Plan?

App Service Plan (P1V2 and S1). The app service plan has 3 (4) apps. 2 webapps, 1 staging slot (production only) and 1 function app. For all apps I switched to 64bit and 'Always On'. Doing this did not make a difference.

If Consumption, how did you deploy?

Azure Pipelines: The resources are created with a Bicep template and the deploy is done from a YAML pipeline (see below)

Are you using the v1 runtime, or the v2 runtime?

v4 Runtime

Are you setting WEBSITE_TIME_ZONE?

Yes, for all apps in the service plan: W. Europe Standard Time

What is your CRON expression set to, and what is your expectation about what it means.

I tried several and I am aware that there was a BUG on the part of Microsoft with timezones and timetriggers (in 2018).

Currently I am doing some basic CRON expression to rule out as much as possible, but still it won't fire.

"0 0 0 * * *" which I expect to run once per day, during night.

"0 0 0 * * 0" which I expect to run once per week, on Sunday?.

"0 * * * * *" every minute, which is for testing only, should be once per hour during weekdays between 09:00 and 20:00

Give a specific UTC time at which you expected your function to get called, and found that it wasn't. Also, explain how you are determining that it is not getting called. If some cases, the function may get called, but it may not be obvious due to some logging issue.

I am using various logs within the Azure portal. Application Insights and the monitoring graphs in the Azure Function and within the Functions itself

And most importantly, include a sample invocation ID so we can find your app and look into the issue.

For the most part I can't, since I can't fire them manually and they are not firing by itself.

2023-03-01 23:00:06.840: Executing 'historytimer' (Reason='Timer fired at 2023-03-02T00:00:06.1168496+01:00', Id=b8d964c0-fb54-4e17-af33-a3cb2f7db004)

2023-03-01 23:00:16.215: Executed 'historytimer' (Succeeded, Id=b8d964c0-fb54-4e17-af33-a3cb2f7db004, Duration=10098ms)

resource appServicePlan 'Microsoft.Web/serverfarms@2022-03-01' = {
    name: appServicePlanName
    location: location
    kind: 'windows'
    sku: {
        name: appServicePlanSku (P1V2 or S1, depending environment)
        capacity: 1
    }
}
/* FUNCTION APP */
resource storageAccountArchive 'Microsoft.Storage/storageAccounts@2022-05-01' = {
    name: '${storageName}${stagingEnvironment}'
    location: location
    sku: {
        name: 'Standard_LRS'
    }
    kind: 'Storage'
}

// ARCHIVE FUNCTION
resource applicationInsightsArchive 'Microsoft.Insights/components@2020-02-02' = {
    name: archiveFunctionName
    location: location
    kind: 'web'
    properties: {
        Application_Type: 'web'
        Request_Source: 'rest'
    }
}
resource functionAppArchive 'Microsoft.Web/sites@2022-03-01' = {
    name: archiveFunctionName
    location: location
    kind: 'functionapp'
    identity: {
        type: 'SystemAssigned'
    }
    properties: {
        httpsOnly: true
        virtualNetworkSubnetId: virtualNetwork.properties.subnets[0].id
        serverFarmId: appServicePlan.id
        siteConfig: {
            vnetRouteAllEnabled: true
            http20Enabled: true
            ftpsState: 'Disabled'
            minTlsVersion: '1.2'
            use32BitWorkerProcess: false
            alwaysOn: true
            appSettings: [
                {
                    name: 'AzureWebJobsStorage'
                    value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountArchive.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccountArchive.listKeys().keys[0].value}'
                }
                {
                    name: 'MainStorageAccount'
                    value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccount.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccount.listKeys().keys[0].value}'
                }
                {
                    name: 'AzureKeyVaultUrl'
                    value: keyVault.properties.vaultUri
                }
                {
                    name: 'WEBSITE_CONTENTAZUREFILECONNECTIONSTRING'
                    value: 'DefaultEndpointsProtocol=https;AccountName=${storageAccountArchive.name};EndpointSuffix=${environment().suffixes.storage};AccountKey=${storageAccountArchive.listKeys().keys[0].value}'
                }
                {
                    name: 'WEBSITE_CONTENTSHARE'
                    value: toLower(archiveFunctionName)
                }
                {
                    name: 'FUNCTIONS_EXTENSION_VERSION'
                    value: '~4'
                }
                {
                    name: 'WEBSITE_NODE_DEFAULT_VERSION'
                    value: '~10'
                }
                {
                    name: 'APPINSIGHTS_INSTRUMENTATIONKEY'
                    value: applicationInsightsArchive.properties.InstrumentationKey
                }
                {
                    name: 'FUNCTIONS_WORKER_RUNTIME'
                    value: 'dotnet'
                }
                {
                    name: 'WEBSITE_RUN_FROM_PACKAGE'
                    value: '1'
                }
                {
                    name: 'WEBSITE_TIME_ZONE'
                    value: 'W. Europe Standard Time'
                }
            ]
        }
    }
}
- task: UseDotNet@2
  displayName: Install .NET 6 SDK 6.0.111
  inputs:
    packageType: sdk
    version: '6.0.111'
    installationPath: $(Agent.ToolsDirectory)/dotnet
    includePreviewVersions: false

- task: VSBuild@1
  displayName: Build SLN
  inputs:
    solution: '**/*.csproj'

- task: DotNetCoreCLI@2
  displayName: Publish Archive Worker
  inputs:
    command: publish
    arguments: '--configuration Release --output publish_output_archive'
    projects: '**/*.csproj'
    publishWebProjects: false
    modifyOutputPath: false
    zipAfterPublish: true


- task: AzureFunctionApp@1 
  displayName: Deploy Archive Worker
  inputs:
    azureSubscription: '${{ parameters.appName }}-${{ parameters.environment }}'
    appType: functionApp
    appName: '${{ parameters.appName }}-${{ parameters.environment }}-archivefunction'
    package: 'publish_output_archive/**/*.zip'
    enableCustomDeployment: true
    deploymentType: runFromZip

Azure Functions
Azure Functions
An Azure service that provides an event-driven serverless compute platform.
2,773 questions
No comments
{count} votes

1 answer

Sort by: Most helpful
  1. MughundhanRaveendran-MSFT 12,121 Reputation points Microsoft Employee
    2023-03-08T09:23:14.65+00:00

    @Bob Meijwaard

    Internally, the Timer triggers are executed on only one instance of the Function App. This is ensured by using a lock which is created on the file in the Storage Account.

    This lock is created by the name of the function App ‘appname’, which acts as a unique host id. In case of the staging slot, the unique host id would be ‘appname-slotname’.

    However, if the Function App name extends the character size of 32 alphabets, the string appended to the unique host id for the staging slot is completely truncated to 32 characters max. This results in the unique host id for both the production and the staging host to be the same. This issue is not related only to Timer Triggers. Here is the documentation which describes the limitation of 32 characters.

    Therefore, when the Function executes, only one of the slots (the first one) can acquire the lock and hence only one of them is able to execute.

    In other words,

    It is possible that depending on the length of your name that the staging slot is holding the blob lease in the storage account (if they are both pointing to same storage) preventing the production slot from running. And we truncate the name to 32 characters when creating the blob leases, so anything longer could cause issues where they are competing for the lease.

    Recommendation:

    • Function app name should be less than 32 characters
    • Unfortunately, there exists no means to rename a function, so you must, therefore, delete and recreate it with a new compliant name.
    • Read the public documentation that discusses Host IDs here

    Or