This is the multi-page printable view of this section. Click here to print.
Dapr Python SDK 扩展
1 - Dapr Python gRPC 服务扩展入门
Dapr Python SDK 提供了一个内置的 gRPC 服务器扩展 dapr.ext.grpc,用于创建 Dapr 服务。
安装
您可以通过以下命令下载并安装 Dapr gRPC 服务器扩展:
pip install dapr-ext-grpc
注意
开发包包含的功能和行为将与 Dapr 运行时的预发布版本兼容。在安装 <code>dapr-dev</code> 包之前,请确保卸载 Python SDK 扩展的任何稳定版本。
pip3 install dapr-ext-grpc-dev
示例
App 对象可用于创建服务器。
监听服务调用请求
InvokeMethodReqest 和 InvokeMethodResponse 对象可用于处理传入请求。
一个简单的监听并响应请求的服务如下所示:
from dapr.ext.grpc import App, InvokeMethodRequest, InvokeMethodResponse
app = App()
@app.method(name='my-method')
def mymethod(request: InvokeMethodRequest) -> InvokeMethodResponse:
print(request.metadata, flush=True)
print(request.text(), flush=True)
return InvokeMethodResponse(b'INVOKE_RECEIVED', "text/plain; charset=UTF-8")
app.run(50051)
完整示例可在此处找到。
订阅主题
在订阅主题时,您可以指示 Dapr 已接受传递的事件,还是应该丢弃该事件或稍后重试。
from typing import Optional
from cloudevents.sdk.event import v1
from dapr.ext.grpc import App
from dapr.clients.grpc._response import TopicEventResponse
app = App()
# 主题的默认订阅
@app.subscribe(pubsub_name='pubsub', topic='TOPIC_A')
def mytopic(event: v1.Event) -> Optional[TopicEventResponse]:
print(event.Data(),flush=True)
# 返回 None(或不显式返回)等效于
# 返回 TopicEventResponse("success")。
# 您也可以返回 TopicEventResponse("retry") 让 dapr 记录
# 该消息并稍后重试传递,或返回 TopicEventResponse("drop")
# 让其丢弃该消息
return TopicEventResponse("success")
# 使用发布订阅路由的特定处理程序
@app.subscribe(pubsub_name='pubsub', topic='TOPIC_A',
rule=Rule("event.type == \"important\"", 1))
def mytopic_important(event: v1.Event) -> None:
print(event.Data(),flush=True)
# 禁用主题验证的处理程序
@app.subscribe(pubsub_name='pubsub-mqtt', topic='topic/#', disable_topic_validation=True,)
def mytopic_wildcard(event: v1.Event) -> None:
print(event.Data(),flush=True)
app.run(50051)
完整示例可在此处找到。
设置输入绑定触发器
from dapr.ext.grpc import App, BindingRequest
app = App()
@app.binding('kafkaBinding')
def binding(request: BindingRequest):
print(request.text(), flush=True)
app.run(50051)
完整示例可在此处找到。
相关链接
2 - Dapr Python SDK 与 FastAPI 集成
Dapr Python SDK 通过 dapr-ext-fastapi 扩展提供与 FastAPI 的集成。
安装
您可以通过以下命令下载并安装 Dapr FastAPI 扩展:
pip install dapr-ext-fastapi
注意
开发版包将包含与 Dapr 运行时预发布版本兼容的功能和行为。在安装 <code>dapr-dev</code> 包之前,请确保卸载任何稳定版本的 Python SDK 扩展。
pip install dapr-ext-fastapi-dev
示例
订阅不同类型的事件
import uvicorn
from fastapi import Body, FastAPI
from dapr.ext.fastapi import DaprApp
from pydantic import BaseModel
class RawEventModel(BaseModel):
body: str
class User(BaseModel):
id: int
name: str
class CloudEventModel(BaseModel):
data: User
datacontenttype: str
id: str
pubsubname: str
source: str
specversion: str
topic: str
traceid: str
traceparent: str
tracestate: str
type: str
app = FastAPI()
dapr_app = DaprApp(app)
# 允许处理任何结构的事件(最简单,但最不健壮)
# dapr publish --publish-app-id sample --topic any_topic --pubsub pubsub --data '{"id":"7", "desc": "good", "size":"small"}'
@dapr_app.subscribe(pubsub='pubsub', topic='any_topic')
def any_event_handler(event_data = Body()):
print(event_data)
# 为了健壮性,根据发布者是否使用 CloudEvents 选择以下方式之一
# 处理使用 CloudEvents 发送的事件
# dapr publish --publish-app-id sample --topic cloud_topic --pubsub pubsub --data '{"id":"7", "name":"Bob Jones"}'
@dapr_app.subscribe(pubsub='pubsub', topic='cloud_topic')
def cloud_event_handler(event_data: CloudEventModel):
print(event_data)
# 处理不使用 CloudEvents 发送的原始事件
# curl -X "POST" http://localhost:3500/v1.0/publish/pubsub/raw_topic?metadata.rawPayload=true -H "Content-Type: application/json" -d '{"body": "345"}'
@dapr_app.subscribe(pubsub='pubsub', topic='raw_topic')
def raw_event_handler(event_data: RawEventModel):
print(event_data)
if __name__ == "__main__":
uvicorn.run(app, host="0.0.0.0", port=30212)
创建 actor
from fastapi import FastAPI
from dapr.ext.fastapi import DaprActor
from demo_actor import DemoActor
app = FastAPI(title=f'{DemoActor.__name__}Service')
# 添加 Dapr Actor 扩展
actor = DaprActor(app)
@app.on_event("startup")
async def startup_event():
# 注册 DemoActor
await actor.register_actor(DemoActor)
@app.get("/GetMyData")
def get_my_data():
return "{'message': 'myData'}"
3 - Dapr Python SDK 与 Flask 集成
Dapr Python SDK 通过 flask-dapr 扩展提供与 Flask 的集成。
安装
你可以使用以下命令下载并安装 Dapr Flask 扩展:
pip install flask-dapr
注意
开发包将包含与 Dapr runtime 预发布版本兼容的功能和行为。在安装 <code>dapr-dev</code> 包之前,请确保卸载任何稳定版本的 Python SDK 扩展。
pip install flask-dapr-dev
示例
from flask import Flask
from flask_dapr.actor import DaprActor
from dapr.conf import settings
from demo_actor import DemoActor
app = Flask(f'{DemoActor.__name__}Service')
# 启用 DaprActor Flask 扩展
actor = DaprActor(app)
# 注册 DemoActor
actor.register_actor(DemoActor)
# 设置方法路由
@app.route('/GetMyData', methods=['GET'])
def get_my_data():
return {'message': 'myData'}, 200
# 运行应用
if __name__ == '__main__':
app.run(port=settings.HTTP_APP_PORT)
4 - Dapr Python SDK 与 Dapr 工作流扩展集成
Dapr Python SDK 提供了一个内置的 Dapr 工作流扩展 dapr.ext.workflow,用于创建 Dapr 服务。
安装
您可以通过以下命令下载并安装 Dapr 工作流扩展:
pip install dapr-ext-workflow
Note
开发版包将包含与 Dapr 运行时预发布版本兼容的功能和行为。在安装 <code>dapr-dev</code> 包之前,请确保已卸载任何稳定版本的 Python SDK 扩展。
pip install dapr-ext-workflow-dev
示例
from time import sleep
import dapr.ext.workflow as wf
wfr = wf.WorkflowRuntime()
@wfr.workflow(name='random_workflow')
def task_chain_workflow(ctx: wf.DaprWorkflowContext, wf_input: int):
try:
result1 = yield ctx.call_activity(step1, input=wf_input)
result2 = yield ctx.call_activity(step2, input=result1)
except Exception as e:
yield ctx.call_activity(error_handler, input=str(e))
raise
return [result1, result2]
@wfr.activity(name='step1')
def step1(ctx, activity_input):
print(f'Step 1: Received input: {activity_input}.')
# Do some work
return activity_input + 1
@wfr.activity
def step2(ctx, activity_input):
print(f'Step 2: Received input: {activity_input}.')
# Do some work
return activity_input * 2
@wfr.activity
def error_handler(ctx, error):
print(f'Executing error handler: {error}.')
# Do some compensating work
if __name__ == '__main__':
wfr.start()
sleep(10) # wait for workflow runtime to start
wf_client = wf.DaprWorkflowClient()
instance_id = wf_client.schedule_new_workflow(workflow=task_chain_workflow, input=42)
print(f'Workflow started. Instance ID: {instance_id}')
state = wf_client.wait_for_workflow_completion(instance_id)
print(f'Workflow completed! Status: {state.runtime_status}')
wfr.shutdown()
- 了解有关编写和管理工作流的更多信息:
- 访问 Python SDK 示例 获取代码示例和尝试 Dapr 工作流的说明:
后续步骤
Dapr 工作流 Python SDK 入门4.1 - Dapr Workflow Python SDK 入门
让我们创建一个 Dapr 工作流并通过控制台调用它。借助提供的工作流示例,你将:
- 运行一个 Python 控制台应用程序,该程序演示包含活动、子工作流和外部事件的工作流编排
- 了解如何处理重试、超时以及工作流状态管理
- 使用 Python 工作流 SDK 来启动、暂停、恢复和清理工作流实例
本示例使用自托管模式下通过 dapr init 初始化的默认配置。
在 Python 示例项目中,simple.py 文件包含应用程序的设置,包括:
- 工作流定义
- 工作流活动定义
- 工作流和工作流活动的注册
前置条件
- 已安装 Dapr CLI
- 已初始化 Dapr 环境
- 已安装 Python 3.9+
- 已安装 Dapr Python 包和工作流扩展
- 验证你使用的是最新的 proto 绑定
设置环境
首先克隆 [Python SDK 仓库]。
git clone https://github.com/dapr/python-sdk.git
从 Python SDK 根目录导航到 Dapr Workflow 示例。
cd examples/workflow
运行以下命令,安装使用 Dapr Python SDK 运行此工作流示例所需的所有依赖。
pip3 install -r workflow/requirements.txt
在本地运行应用程序
要运行 Dapr 应用程序,你需要启动 Python 程序和一个 Dapr 边车。在终端中运行:
dapr run --app-id wf-simple-example --dapr-grpc-port 50001 --resources-path components -- python3 simple.py
注意: 由于 Windows 上未定义 Python3.exe,你可能需要使用
python simple.py而不是python3 simple.py。
预期输出
- "== APP == Hi Counter!"
- "== APP == New counter value is: 1!"
- "== APP == New counter value is: 11!"
- "== APP == Retry count value is: 0!"
- "== APP == Retry count value is: 1! This print statement verifies retry"
- "== APP == Appending 1 to child_orchestrator_string!"
- "== APP == Appending a to child_orchestrator_string!"
- "== APP == Appending a to child_orchestrator_string!"
- "== APP == Appending 2 to child_orchestrator_string!"
- "== APP == Appending b to child_orchestrator_string!"
- "== APP == Appending b to child_orchestrator_string!"
- "== APP == Appending 3 to child_orchestrator_string!"
- "== APP == Appending c to child_orchestrator_string!"
- "== APP == Appending c to child_orchestrator_string!"
- "== APP == Get response from hello_world_wf after pause call: Suspended"
- "== APP == Get response from hello_world_wf after resume call: Running"
- "== APP == New counter value is: 111!"
- "== APP == New counter value is: 1111!"
- "== APP == Workflow completed! Result: "Completed"
发生了什么?
当你运行应用程序时,会演示几个关键的工作流功能:
工作流和活动注册:应用程序使用 Python 装饰器自动向运行时注册工作流和活动。这种基于装饰器的方法提供了一种简洁、声明式的方式来定义你的工作流组件:
@wfr.workflow(name='hello_world_wf') def hello_world_wf(ctx: DaprWorkflowContext, wf_input): # Workflow definition... @wfr.activity(name='hello_act') def hello_act(ctx: WorkflowActivityContext, wf_input): # Activity definition...运行时设置:应用程序初始化工作流运行时和客户端:
wfr = WorkflowRuntime() wfr.start() wf_client = DaprWorkflowClient()活动执行:工作流执行一系列活动来递增计数器:
@wfr.workflow(name='hello_world_wf') def hello_world_wf(ctx: DaprWorkflowContext, wf_input): yield ctx.call_activity(hello_act, input=1) yield ctx.call_activity(hello_act, input=10)重试逻辑:工作流演示了使用重试策略进行错误处理:
retry_policy = RetryPolicy( first_retry_interval=timedelta(seconds=1), max_number_of_attempts=3, backoff_coefficient=2, max_retry_interval=timedelta(seconds=10), retry_timeout=timedelta(seconds=100), ) yield ctx.call_activity(hello_retryable_act, retry_policy=retry_policy)子工作流:子工作流使用自己的重试策略执行:
yield ctx.call_child_workflow(child_retryable_wf, retry_policy=retry_policy)外部事件处理:工作流等待一个带有超时的外部事件:
event = ctx.wait_for_external_event(event_name) timeout = ctx.create_timer(timedelta(seconds=30)) winner = yield when_any([event, timeout])工作流生命周期管理:示例演示如何暂停和恢复工作流:
wf_client.pause_workflow(instance_id=instance_id) metadata = wf_client.get_workflow_state(instance_id=instance_id) # ... check status ... wf_client.resume_workflow(instance_id=instance_id)事件触发:恢复后,工作流触发一个事件:
wf_client.raise_workflow_event( instance_id=instance_id, event_name=event_name, data=event_data )完成与清理:最后,工作流等待完成并进行清理:
state = wf_client.wait_for_workflow_completion( instance_id, timeout_in_seconds=30 ) wf_client.purge_workflow(instance_id=instance_id)