Azure / Azure/azure-functions-host
Python (V2) blob output-bindings get created but stay empty
- Dominant language
- C#
- Stars
- 2k
- Forks
- 482
- Avg merge
- 2d 12h
- Merged PRs (30d)
- 38
Description
When using multiple `blob_output` decorators to create blob output bindings for a Python Function (V2) the blobs are created, but no data is uploaded and the blobs stay empty.
#### Repro steps
1. create app service plan from Premium V3
- e.g. pricing plan: P0V3
1. create function app (and implicit config storage account)
- deployment: code
- runtime stack: Python
- Version: 3.10
- OS: Linux
1. create separate storage account for output
- performance: standard
- redundancy: GRS
- Hierarchical Namespace: yes
1. create container in output storage account
1. create SAS token for output storage account and set it as env variable in function app
1. create function using func core tools (version 4.0.5441)
- e.g. `func init demofunc --python -m V2`
1. add code (see snippet below)
1. deploy code to function app
1. generate load to function (causing it to output blobs)
#### Expected behavior
All blobs are written correctly using output bindings, i.e. none of them are empty after the function returned successfully.
#### Actual behavior
Some blobs stay empty when using blob_output binding, e.g. when running 2048 calls (supposed to generate 4096 blobs) between 15-25 remain empty, even though the function returned successfully every time. (HTTP status-code 200 in this case).
#### Known workarounds
Use a library to write to the blob storage instead of an output binding. Tested with `azure-storage-file-datalake`.
Also it seems that changing the application plan to Premium V2 (e.g. P1V2) solves the problem.
#### Related information
Provide any related information
* Programming language used: Python (V2)
* source: see below
* Bindings used: blob output binding
Source
```python
import logging
import random
import azure.functions as func
BLOB_SIZE = 32 * 1024
app = func.FunctionApp(http_auth_level=func.AuthLevel.FUNCTION)
@app.route(route="use_binding")
@app.blob_output(
arg_name="blob01",
path="output/binding/{rand-guid}.dat",
connection="outputBlobStorage",
)
@app.blob_output(
arg_name="blob02",
path="output/binding/{rand-guid}.dat",
connection="outputBlobStorage",
)
async def write_blobs_with_binding(
req: func.HttpRequest,
blob01: func.Out[str],
blob02: func.Out[str],
) -> func.HttpResponse:
try:
blob01.set(random.randbytes(BLOB_SIZE))
blob02.set(random.randbytes(BLOB_SIZE))
except Exception as e:
logging.exception(e)
return func.HttpResponse(f"EXCEPTION: {e}", status_code=500)
return func.HttpResponse("OK", status_code=200)
```
Contributor guide
Assessment
This issue has not been assessed yet.