Azure / Azure/azure-functions-durable-python

purge_instance_history_by raises exception when optional created_time_from is not passed

未关闭
#470 0 条评论 0 个 reaction 已指派 0 人 在 GitHub 查看
bug fixed-in-v2 P2
主要语言
Python
星标
157
派生
70
平均合并
2 天 10 小时
30 天内合并 PR
2

描述

🐛 **Describe the bug**
> A clear and concise description of what the bug is.

When `created_time_from: Optional[datetime] = None` is not passed to `purge_instance_history_by` it causes an exception in `delete_async_request`.

![image](https://github.com/Azure/azure-functions-durable-python/assets/122284839/d64b0440-cdc2-449b-a809-653076a6a19d)

```
Exception has occurred: Exception
The operation failed with an unexpected status code 400
File "/home/andre/code/durable-function/.venv/lib/python3.10/site-packages/azure/durable_functions/models/DurableOrchestrationClient.py", line 413, in purge_instance_history_by
return self._parse_purge_instance_history_response(response)
File "/home/andre/code/durable-function/function_app.py", line 15, in http_clean
result = await client.purge_instance_history_by(
File "/home/andre/code/durable-function/.venv/lib/python3.10/site-packages/azure/durable_functions/decorators/durable_app.py", line 199, in df_client_middleware
return await user_code(*args, **kwargs)
File "/usr/lib/azure-functions-core-tools-4/workers/python/3.10/LINUX/X64/azure_functions_worker/extension.py", line 147, in get_async_invocation_wrapper
result = await function(**args)
File "/usr/lib/azure-functions-core-tools-4/workers/python/3.10/LINUX/X64/azure_functions_worker/dispatcher.py", line 758, in _run_async_func
return await ExtensionManager.get_async_invocation_wrapper(
File "/usr/lib/azure-functions-core-tools-4/workers/python/3.10/LINUX/X64/azure_functions_worker/dispatcher.py", line 475, in _handle__invocation_request
call_result = await self._run_async_func(
File "/usr/lib/azure-functions-core-tools-4/workers/python/3.10/LINUX/X64/azure_functions_worker/dispatcher.py", line 261, in _dispatch_grpc_request
resp = await request_handler(request)
File "/usr/lib/python3.10/asyncio/events.py", line 80, in _run
self._context.run(self._callback, *self._args)
File "/usr/lib/python3.10/asyncio/base_events.py", line 1909, in _run_once
handle._run()
File "/usr/lib/python3.10/asyncio/base_events.py", line 603, in run_forever
self._run_once()
File "/usr/lib/python3.10/asyncio/base_events.py", line 636, in run_until_complete
self.run_forever()
File "/usr/lib/python3.10/asyncio/runners.py", line 44, in run
return loop.run_until_complete(main)
File "/usr/lib/azure-functions-core-tools-4/workers/python/3.10/LINUX/X64/azure_functions_worker/main.py", line 49, in main
return aio_compat.run(start_async(
File "/usr/lib/azure-functions-core-tools-4/workers/python/3.10/LINUX/X64/worker.py", line 74, in
main.main()
File "/usr/lib/python3.10/runpy.py", line 86, in _run_code
exec(code, run_globals)
File "/usr/lib/python3.10/runpy.py", line 196, in _run_module_as_main
return _run_code(code, main_globals, None,
Exception: The operation failed with an unexpected status code 400
```

🤔 **Expected behavior**
> What should have happened?

Clean instances older than `created_time_to`. Or `purge_instance_history_by` not to allow `None` in `created_time_to`.

☕ **Steps to reproduce**
> What Durable Functions patterns are you using, if any?

> Any minimal reproducer we can use?

Yes. function_app.py below replicates the issue.

```python3
import azure.functions as func
import azure.durable_functions as df
from datetime import datetime, timedelta

app = df.DFApp(http_auth_level=func.AuthLevel.ANONYMOUS)

@app.route(route="clean")
@app.durable_client_input(client_name="client")
async def http_clean(req: func.HttpRequest, client: df.DurableOrchestrationClient):
now = datetime.today()
created_time_to = now + timedelta(minutes=1) # leave at least 1 mins

# Clean up function
result = await client.purge_instance_history_by(
created_time_to=created_time_to,
)
return f"Cleaned {result.instances_deleted}"
```

For example if only `created_time_from` is passed, it works as expected and the entries are deleted but if only `created_time_to` is passed, it throws the 400 exception.
```python3
created_time_from = now - timedelta(hours=50)
# Clean up function
result = await client.purge_instance_history_by(
created_time_from=created_time_from,
)
```

> Are you running this locally or on Azure?

Locally.

```
azure-functions==1.17.0
azure-functions-durable==1.2.8
```

⚡**If deployed to Azure**
> We have access to a lot of telemetry that can help with investigations. Please provide as much of the following information as you can to help us investigate!

- **Timeframe issue observed**:
- **Function App name**:
- **Function name(s)**:
- **Azure region**:
- **Orchestration instance ID(s)**:
- **Azure storage account name**:

> If you don't want to share your Function App or storage account name GitHub, please at least share the orchestration instance ID. Otherwise it's extremely difficult to look up information.

贡献指南

打开贡献指南

调研方向

从 azure/durable_functions/models/DurableOrchestrationClient.py 中的 purge_instance_history_by 开始,重点检查在第 413 行附近到达 delete_async_request 的路径。使用仅包含 created_time_to 的 function_app.py 示例重现该问题,然后将其与正常工作的 created_time_from 情况进行比较。当仅使用 created_time_to 进行清理时不再返回报告的 400 错误,即表示完成。

由索引模型根据 Issue 内容生成。

评估

技术栈
azure, python
领域
api, backend, cloud
Issue 类型
缺陷
难度
2/5
预计耗时
1-3 小时
活跃度
停滞
描述清晰度
基本清楚
新手友好度
42/100

把新 issue 发到你的邮箱

精选适合新手参与的 GitHub issue 摘要。