Azure / azure-functions-core-tools

Command line tools for Azure Functions
MIT License
1.32k stars 434 forks source link

Unable to publish .NET5 function app without forcing wrong worker runtime value #2524

Closed gzdorik-brightgrove closed 3 years ago

gzdorik-brightgrove commented 3 years ago

I've created a function app on azure using following command

az functionapp create --name <APP_NAME> --storage-account <STORAGE_ACC> --plan <SERVICE_PLAN> --resource-group <RESOURCE_GROUP> --runtime dotnet-isolated --runtime-version 5.0 --functions-version 3

Created a .NET5 function project using func init and selecting dotnet isolated option.

When I try to publish the app

func azure functionapp publish <APP_NAME>

I get following message: Your Azure Function App has 'FUNCTIONS_WORKER_RUNTIME' set to 'dotnetIsolated' while your local project is set to 'None'.

If I specify the language in the end of the command

func azure functionapp publish <APP_NAME> --csharp

I still get the error: Your Azure Function App has 'FUNCTIONS_WORKER_RUNTIME' set to 'dotnetIsolated' while your local project is set to 'dotnet'..

So each time I deploy the function I have to use the --force switch and update the value on Azure Portal after the Function app is deployed.

RyanMarcotte commented 3 years ago

I am receiving the same error message when attempting to publish my function app within an Azure DevOps release pipeline

# using Azure CLI task to execute the following...
func azure functionapp publish bn-fapp-square-catalog-dev --build remote --csharp
Your Azure Function App has 'FUNCTIONS_WORKER_RUNTIME' set to 'dotnetIsolated' while your local project is set to 'dotnet'.
NeilMacMullen commented 3 years ago

Same here - anyone know of a workaround?

ryanhubbell commented 3 years ago

I only seem to have this problem when trying to deploy via azure pipelines. I can publish from my local machine without issue.

NeilMacMullen commented 3 years ago

I should have been clearer in my previous comment - I definitely see the problem when deploying from my local machine.

ryanhubbell commented 3 years ago

Ok the problem was my own fault. It's because I didn't check in the local.settings.json file into source control, so when Azure pipelines ran the job, it didn't know the language, or runtime. Once I added that file to the repo, things published fine.

RyanMarcotte commented 3 years ago

When the local.settings.json file is checked into source control and is used by Azure Pipelines to perform the deployment, how do the AzureWebJobsStorage and AzureWebJobsDashboard affect things?

{
    "IsEncrypted": false,
    "Values": {
        "AzureWebJobsStorage": "UseDevelopmentStorage=true",
        "AzureWebJobsDashboard": "UseDevelopmentStorage=true",
        "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated"
    }
}
asparrowhawk commented 3 years ago

@RyanMarcotte I have been having the same issue, but have been using a cut down local.settings.json file in the same publish output directory:

{
  "IsEncrypted": false,
  "Values": {
    "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated"
  }
}

As I expect the additional values, for AzureWebJobsStorage etc, would overwrite those already setup in Azure.

ryanhubbell commented 3 years ago

FWIW, I just checked my deployment, and the AzureWebJobsStorage property was not overridden. (I didn't have the AzureWebJobsDashboard property in my json file).

NeilMacMullen commented 3 years ago

Turns out my issue was due to not copying local.settings.json to the correct folder. Now works fine.

RyanMarcotte commented 3 years ago

As I expect the additional values, for AzureWebJobsStorage etc, would overwrite those already setup in Azure.

@asparrowhawk , are you getting errors related to a null connection string when running the functions locally using func host start and the local.settings.json you posted? My function is timer-based.

image

RyanMarcotte commented 3 years ago

FWIW, I just checked my deployment, and the AzureWebJobsStorage property was not overridden.

@ryanidev , you mean that the AzureWebJobsStorage property is present in your local.settings.json file and the value from that file does not override the value in Azure Portal when the app is published?

asparrowhawk commented 3 years ago

@asparrowhawk , are you getting errors related to a null connection string when running the functions locally using func host start and the local.settings.json you posted? My function is timer-based.

I do not see the issue with the connection string in my simple example:

    public class Timer
    {
        [Function("Periodic")]
        [QueueOutput("AzureWebJobsStorage")]
        public static Task<string> Execute([TimerTrigger(
#if DEBUG
                "*/5 * * * * *"
                , RunOnStartup = true
#else
              "0 */3 * * * *"
#endif
            )]
            TimerInfo timer,
            FunctionContext executionContext)
        {
            var logger = executionContext.GetLogger("Periodic");
            var last = timer?.ScheduleStatus?.Last ?? DateTime.Now;
            var next = timer?.ScheduleStatus?.Next ?? last.Add(TimeSpan.FromSeconds(5));
            logger.LogInformation($"C# Timer trigger function processed a request. Next trigger: {next.ToUniversalTime()}");

            var lastutc = last.ToUniversalTime();
            var result = JsonSerializer.Serialize
            (
                new { lastutc.Day, lastutc.Month, lastutc.Year, lastutc.Hour, lastutc.Minute, lastutc.Second }
            );
            return Task.FromResult(result);
        }
    }
Connect-AzAccount
dotnet publish -c Release
cd .\bin\Release\net5.0\publish

Add cut down local.settings.json file to the publish directory

func azure functionapp publish sparrowhawk-net5functions
Getting site publishing info...
Creating archive for current directory...
Uploading 10.93 MB [##############################################################################]
Upload completed successfully.
Deployment completed successfully.
Syncing triggers...
Syncing triggers...
Syncing triggers...
Functions in sparrowhawk-net5functions:
    Periodic - [TimerTrigger]

Note: only Windows is currently supported for .NET 5.0 function apps.

ryanhubbell commented 3 years ago

FWIW, I just checked my deployment, and the AzureWebJobsStorage property was not overridden.

@ryanidev , you mean that the AzureWebJobsStorage property is present in your local.settings.json file and the value from that file does not override the value in Azure Portal when the app is published?

yes, that is what I observed. Although I only tested once...I've had issues before where I had to publish twice to actually see my changes ¯_(ツ)_/¯

RyanMarcotte commented 3 years ago

I checked local.settings.json file into source control as previously described.

{
    "IsEncrypted": false,
    "Values": {
        "AzureWebJobsStorage": "UseDevelopmentStorage=true",
        "AzureWebJobsDashboard": "UseDevelopmentStorage=true",
        "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated"
    }
}

Also checked the following local.settings.json file into source control, located in a deploy folder off the repository root.

{
    "IsEncrypted": false,
    "Values": {
        "AzureWebJobsStorage": "#{AzureStorageAccountConnectionString}#",
        "AzureWebJobsDashboard": "#{AzureStorageAccountConnectionString}#",
        "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated"
    }
}

In my build pipeline, I include both the original local.settings.json file and the deploy/local.settings.json file as part of the published build artifact.

During the deployment pipeline, I use the replace tokens task to replace the #{AzureStorageAccountConnectionString}# placeholder with the like-named value from a variable group (the variable group is linked to an Azure Key Vault). Then I overwrite the local.settings.json file in the function folder with the deploy/local.settings.json file (which now holds the real connection strings).

This process ensures that development storage is used when running the functions locally and the actual connection string is used when deploying to Azure.

... now I just have to figure out how to include a company NuGet repository (hosted by Azure Artifacts) when performing remote builds, as that is the only thing failing for me now. Deploying to Linux.

func azure functionapp publish bn-fapp-square-catalog-dev --build remote --publish-local-settings -i --overwrite-settings -y
RyanMarcotte commented 3 years ago

Figured out the NuGet authentication issue. I added a "NuGet authentication" task to the deployment pipeline, changed to use local build, and included the NuGet sources in the Azure Function Core Tools command that performs the build + deployment.

func azure functionapp publish bn-fapp-square-catalog-dev --build local --publish-local-settings -i --overwrite-settings -y --dotnet-cli-params " --source https://api.nuget.org/v3/index.json --source [censored] --source [censored]"
gzdorik-brightgrove commented 3 years ago

I've updated to the latest version available:

❯ func --version
3.0.3477

But I still get the same error:

❯ func azure functionapp publish my-functions
Can't determine project language from files. Please use one of [--csharp, --javascript, --typescript, --java, --python, --powershell, --custom]
Your Azure Function App has 'FUNCTIONS_WORKER_RUNTIME' set to 'dotnetIsolated' while your local project is set to 'None'.
You can pass --force to update your Azure app with 'None' as a `'FUNCTIONS_WORKER_RUNTIME'

local.settings.json

{
  "IsEncrypted": false,
  "Values": {
    "FUNCTIONS_WORKER_RUNTIME": "dotnet-isolated",
  }
}
asparrowhawk commented 3 years ago

@gzdorik-brightgrove Have you changed to the build output directory or publish directory before you issue the func azure functionapp publish command? Is the local.settings.json file present in the directory? The only time I saw "Can't determine project language ..." message was when the local.settings.json file was not present in the directory.

For your information:

❯ func --version
3.0.3442
gzdorik-brightgrove commented 3 years ago

@asparrowhawk Checked the output publish directory and did not find local.settings.json file there. Then I checked the project file and saw this:

<None Update="local.settings.json">
  <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
  <CopyToPublishDirectory>Never</CopyToPublishDirectory>
</None>

Removed the CopyToPublishDirectory element and it worked! Publish finished successfully without any errors. So it seems the CLI tools that creates a Functions project puts that element there and the element should be removed manually.

Thank you for your help.