Fix: “0 functions loaded” deploying Azure Functions from package
This post is mainly a reminder to myself, because i’ve made the same mistake a few times in different projects.
How and why to deploy Azure functions from a package
When using Azure Functions, you can simplify deployment and maintenance of your function by deploying from a package file rather than directly in to the function. This also has the benefit of reducing cold start times, particularly where there are a large number of dependencies.
To deploy from a package (without using the Azure deployment tools), you:
- Create a zip file with your code and its dependencies
- deploy that zip to Azure
- Set the
WEBSITE_RUN_FROM_PACKAGE
property on the function app settings
The WEBSITE_RUN_FROM_PACKAGE
setting can either be a 1
if you’ve deployed your code to the /home/data/SitePackages
folder on the function app, or a URL. I prefer to deploy my code as a zip stored in a blob, as this seems cleaner, and is easier to upgrade.
- Create a container (
app-container
) - Upload the file to a blob called something like
app-blob-datetime
. By appending a timestamp to the blob name, subsequent deployments can be to a new blob (avoiding locking concerns) and then switching over is nearly instant and has almost zero downtime. If desired, it is simple to switch back to a previous version. - Generate a long-lived SAS with
read
privileges scoped on the container (app-container
) - Construct a fully qualified URL to the blob, and set this as the
WEBSITE_RUN_FROM_PACKAGE
setting. - Restart the function app (typically < 1 second).
Error: 0 functions loaded
When browsing to the functions Overview page, we can get invited to “Create functions in your preferred environment”, implying that no functions exist:
Navigating to Monitoring > Logs, and selecting Traces shows something interesting (you may need to enable App Insights and restart the function app). First, we see a message 1 functions found (Custom)
, but immediately after it 0 functions loaded
:
Fix: Ensure all packages are available
In order for the custom package to load, you need to ensure that all of the Python packages that it needs are available. To do this, you must install the packages in to the folder and then zip it. You can do this with Pip, setting the specific output folder e.g.
pip install --disable-pip-version-check --target="build/.python_packages/lib/site-packages" -r app/requirements.txt
Then, when zip the file to include the .python_packages
folder. Here’s my build script, which also ensures that we don’t include any files specified in .funcignore
:
#!/bin/bash
# Remove and recreate the 'build' folder
rm -rf build
mkdir -p build
# export requirements.txt
poetry export --only main --without-hashes -f requirements.txt --output app/requirements.txt
# Copy the contents of the 'app' folder to 'build', including hidden files and folders
shopt -s dotglob
cp -r app/* build/
# Apply .funcignore to the contents of 'build'
if [ -f "app/.funcignore" ]; then
while IFS= read -r pattern; do
find build -name "$pattern" -exec rm -rf {} +
done < app/.funcignore
fi
# https://github.com/Azure/azure-functions-host/issues/9720#issuecomment-2129618480
pip install --disable-pip-version-check --target="build/.python_packages/lib/site-packages" -r app/requirements.txt