Azure / azure-functions-dotnet-worker

Azure Functions out-of-process .NET language worker
MIT License
429 stars 184 forks source link

Required .azurefunctions directory is not created when publishing from a GitHub workflow on an ubuntu runner #1240

Open rellis-of-rhindleton opened 1 year ago

rellis-of-rhindleton commented 1 year ago

This is similar to issue 741. That was closed because the op couldn't reproduce it later, but it's a current issue for me.

When dotnet publish runs on my computer, the publish output contains a folder named .azurefunctions, but when the same commands are run on an ubuntu GitHub runner, that folder is missing. I haven't noticed any other differences. In both cases there is a file named extensions.json which contains references to the .azurefunctions folder, so it seems like the folder is expected to be there.

Deploying the app from my computer's build (which has that folder) runs fine in Azure. Deploying the one built on the GitHub runner (which does not) gets "No job functions found. Try making your job classes and methods public" errors, and the app doesn't work.

The project is an isolated process function app for .NET 7. In both cases I'm using the .NET SDK version 7.0.100.

I'm happy to provide any logs or other diagnostics.

fabiocav commented 1 year ago

Thanks for reporting this, @rellis-of-rhindleton, the folder is indeed required, and its absence will lead to the error you've mentioned.

The information you've shared above is clear and we'll take a closer look to see what is going on with the build process.

Can you confirm what OS you're using when you build locally?

rellis-of-rhindleton commented 1 year ago

For local development I'm using Windows 11 Enterprise, version 21H2.

Here are some specs for the Ubuntu GitHub runner:

.NET 7 is being installed using actions/setup-dotnet@v3. The DOTNET_INSTALL_DIR environment variable is set to ./.dotnet, as a workaround for some permission problems. This is a workaround that was recommended in another issue.

Output of dotnet --info (some values redacted):

.NET SDK:
 Version:   7.0.101
 Commit:    bb24aafa11

Runtime Environment:
 OS Name:     ubuntu
 OS Version:  20.04
 OS Platform: Linux
 RID:         ubuntu.20.04-x64
 Base Path:   WORKSPACE_DIR/REPO_NAME/.dotnet/sdk/7.0.101/

Host:
  Version:      7.0.1
  Architecture: x64
  Commit:       97203d38ba

.NET SDKs installed:
  7.0.101 [WORKSPACE_DIR/REPO_NAME/.dotnet/sdk]

.NET runtimes installed:
  Microsoft.AspNetCore.App 7.0.1 [WORKSPACE_DIR/REPO_NAME/.dotnet/shared/Microsoft.AspNetCore.App]
  Microsoft.NETCore.App 7.0.1 [WORKSPACE_DIR/REPO_NAME/.dotnet/shared/Microsoft.NETCore.App]

Other architectures found:
  None

Environment variables:
  DOTNET_ROOT       [WORKSPACE_DIR/REPO_NAME/.dotnet]

global.json file:
  Not found

The build command:

dotnet publish PROJECT.csproj -c Release -r linux-x64 --no-self-contained -o publish

I've tried using other locations for publish output but it doesn't seem to make any difference.

berhir commented 1 year ago

We are facing the same issue when building our function with Azure Pipelines using the ubuntu-22.04 runner image. It works fine when I change the build definition to use a Windows runner image.

There are at least two differences in the generated output. On Linux, the .azurefunctions folder is missing and there is of course no .exe file.

Using a Windows runner is ok for us as a temporary solution, but the build of our whole project takes twice the time on Windows compared to Linux. So I hope you can find a solution and we can switch back to using a Linux runner soon.

daniellittledev commented 1 year ago

I can also reproduce the issue:

This command is run both locally and on the build agent.

dotnet publish . --configuration Release --output "../output/func" --runtime win10-x86 --self-contained false

The only difference is my local build env is Windows and the build server is Linux.

After analysing the outputs of the two environments, the .azurefunctions is missing in the build server output.

Versions: runs-on: Ubuntu 22.0 dotnet version: 6.0.x

daniellittledev commented 1 year ago

I think I've tracked down my issue, which is the .azurefunctions folder does get generated. However, it is not in the .zip artifact.

In my case this is because I was using Compress-Archive to generate the artifact. Which works correctly on windows, however on linux these are interpreted as hidden files and are not added to the archive. This results in an invalid az function when deployed.

Also see: https://github.com/PowerShell/Microsoft.PowerShell.Archive/issues/66

fabricciotc commented 1 year ago

Yes, you've correctly identified the issue. The problem lies in using Compress-Archive to generate the artifact. While it works correctly on Windows, on Linux, files and folders starting with a dot (such as the .azurefunctions folder) are considered hidden files and are not automatically added to the archive. As a result, when you deploy the artifact, the missing .azurefunctions folder leads to an invalid Azure Function.

To address this, you can modify your approach by explicitly including the .azurefunctions folder in the archive creation process. One possible solution is to use the Get-ChildItem command to retrieve all files and folders, including hidden ones, and then pass them to Compress-Archive for compression.

One possible solution is to use the following code:


Get-ChildItem -Path ./azurefunction-release -Force | Compress-Archive -DestinationPath ./output
skotl commented 1 year ago

Apologies for barging in but for info I've had the same problem with a GitLab CD pipeline. Issue is described as above and 24 hours of banging my head against the wall and googling landed me here!

As @fabricciotc suggested, the solution for me was to force include .azurefunctions in the zip command:

zip -r /deploy.zip * .azurefunctions

The symptom for me was that the function app started but no functions were listed. A push deploy from Rider worked, but the CD pipeline did not. Hope this helps other people who may stumble upon this too.

leroibeukes commented 6 months ago

Apologies for barging in but for info I've had the same problem with a GitLab CD pipeline. Issue is described as above and 24 hours of banging my head against the wall and googling landed me here!

As @fabricciotc suggested, the solution for me was to force include .azurefunctions in the zip command:

zip -r /deploy.zip * .azurefunctions

The symptom for me was that the function app started but no functions were listed. A push deploy from Rider worked, but the CD pipeline did not. Hope this helps other people who may stumble upon this too.

After lots of googling - this is the answer!

Our CI/CD pipeline runs on a linux agent and this folder (.azurefunctions) is excluded from the generated zip file intermittently. (have to run the pipeline more than once for it to appear).

rellis-of-rhindleton commented 6 months ago

So it appears the issue is not with the deployment, but with the zip command and an OS convention. Perhaps this should just be a documentation enhancement?

jrichardsz commented 4 months ago

I tried with net7.0 & net8.0 and the .azurefunctions are perfectly created in linux and windows

linux image

windows image

And the function (http trigger) works as expected

Maybe it is a misconfiguration between nuget package versions, csproj, Program, etc

dotnet cli

.csproj

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net7.0</TargetFramework>
    <AzureFunctionsVersion>v4</AzureFunctionsVersion>
    <OutputType>Exe</OutputType>
  </PropertyGroup>
  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
    <DefineConstants>DEBUG;TRACE</DefineConstants>
  </PropertyGroup>
  <ItemGroup>
    <PackageReference Include="Microsoft.ApplicationInsights.WorkerService" Version="2.22.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker" Version="1.22.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.ApplicationInsights" Version="1.2.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Extensions.Http" Version="3.2.0" />
    <PackageReference Include="Microsoft.Azure.Functions.Worker.Sdk" Version="1.17.2" />
    <PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
    <PackageReference Include="System.Net.NameResolution" Version="4.3.0" />
  </ItemGroup>
  <ItemGroup>
    <None Update="host.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
    </None>
    <None Update="local.settings.json">
      <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
      <CopyToPublishDirectory>Never</CopyToPublishDirectory>
    </None>
  </ItemGroup>
</Project>

local.settings.json

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

commands

dotnet restore
dotnet build -c Release -o .build
dotnet publish -c Release -o .publish
acepoiKT commented 3 months ago

I ran into the same issue and spent hours trying to figure what was going on. The only error I was seeing in Azure was 404 on the HTTP Routes and no functions loaded.

2024-08-13T22:54:23.937 [Information] 0 functions loaded
2024-08-13T22:54:23.952 [Information] Generating 0 job function(s)
2024-08-13T22:54:23.963 [Warning] No job functions found. Try making your job classes and methods public. If you're using binding extensions (e.g. Azure Storage, ServiceBus, Timers, etc.) make sure you've called the registration method for the extension(s) in your startup code (e.g. builder.AddAzureStorage(), builder.AddServiceBus(), builder.AddTimers(), etc.).

After modifying our create archive step to use bash and zip command instead of powershell like leroibeukes recommended, I was able to fix our function in Azure.

Big thanks to rellis-of-rhindleton and leroibeukes for posting this issue.

vndteksysrxa commented 2 months ago

if anyone had this kind of issue with GitHubPipeline upload artifact below options should be used.

include-hidden-files: true

sscowden commented 2 months ago

if anyone had this kind of issue with GitHubPipeline upload artifact below options should be used.

include-hidden-files: true

  • uses: actions/upload-artifact@v4.4.0 with: name: yourSolutionName path: . PathtoFolder if-no-files-found: error include-hidden-files: true

You are a hero. Thank you!

sluhn-HessJa commented 2 months ago

if anyone had this kind of issue with GitHubPipeline upload artifact below options should be used.

include-hidden-files: true

  • uses: actions/upload-artifact@v4.4.0 with: name: yourSolutionName path: . PathtoFolder if-no-files-found: error include-hidden-files: true

Your comment helped me out, thank you! Looks like v4.4.0 had breaking changes and seems include-hidden-files: true is required if you're building artifacts for Azure Functions: https://github.com/actions/upload-artifact/releases/tag/v4.4.0

ChaiyoKung commented 2 months ago

if anyone had this kind of issue with GitHubPipeline upload artifact below options should be used.

include-hidden-files: true

  • uses: actions/upload-artifact@v4.4.0 with: name: yourSolutionName path: . PathtoFolder if-no-files-found: error include-hidden-files: true

Thank you, It work when add include-hidden-files: true. I'm using https://github.com/actions/upload-artifact/releases/tag/v3.2.1

hylander0 commented 1 month ago

Yep. The .azurefunction folder was no longer getting zipped up with breaking change that now requires consumers to include the include-hidden-files: true attribute. If you were targeting @actions/upload-artifact@v4 this will affect you as well.

Thank you @vndteksysrxa for documenting this!