mirror of https://github.com/dapr/docs.git
Merge branch 'v1.15' into redistrim
This commit is contained in:
commit
cb6faa65af
|
|
@ -39,13 +39,14 @@ The Dapr sidecar doesn’t load any workflow definitions. Rather, the sidecar si
|
||||||
Define the workflow activities you'd like your workflow to perform. Activities are a function definition and can take inputs and outputs. The following example creates a counter (activity) called `hello_act` that notifies users of the current counter value. `hello_act` is a function derived from a class called `WorkflowActivityContext`.
|
Define the workflow activities you'd like your workflow to perform. Activities are a function definition and can take inputs and outputs. The following example creates a counter (activity) called `hello_act` that notifies users of the current counter value. `hello_act` is a function derived from a class called `WorkflowActivityContext`.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def hello_act(ctx: WorkflowActivityContext, input):
|
@wfr.activity(name='hello_act')
|
||||||
|
def hello_act(ctx: WorkflowActivityContext, wf_input):
|
||||||
global counter
|
global counter
|
||||||
counter += input
|
counter += wf_input
|
||||||
print(f'New counter value is: {counter}!', flush=True)
|
print(f'New counter value is: {counter}!', flush=True)
|
||||||
```
|
```
|
||||||
|
|
||||||
[See the `hello_act` workflow activity in context.](https://github.com/dapr/python-sdk/blob/master/examples/demo_workflow/app.py#LL40C1-L43C59)
|
[See the task chaining workflow activity in context.](https://github.com/dapr/python-sdk/blob/main/examples/workflow/simple.py)
|
||||||
|
|
||||||
|
|
||||||
{{% /codetab %}}
|
{{% /codetab %}}
|
||||||
|
|
@ -226,19 +227,32 @@ Next, register and call the activites in a workflow.
|
||||||
|
|
||||||
<!--python-->
|
<!--python-->
|
||||||
|
|
||||||
The `hello_world_wf` function is derived from a class called `DaprWorkflowContext` with input and output parameter types. It also includes a `yield` statement that does the heavy lifting of the workflow and calls the workflow activities.
|
The `hello_world_wf` function is a function derived from a class called `DaprWorkflowContext` with input and output parameter types. It also includes a `yield` statement that does the heavy lifting of the workflow and calls the workflow activities.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
def hello_world_wf(ctx: DaprWorkflowContext, input):
|
@wfr.workflow(name='hello_world_wf')
|
||||||
print(f'{input}')
|
def hello_world_wf(ctx: DaprWorkflowContext, wf_input):
|
||||||
|
print(f'{wf_input}')
|
||||||
yield ctx.call_activity(hello_act, input=1)
|
yield ctx.call_activity(hello_act, input=1)
|
||||||
yield ctx.call_activity(hello_act, input=10)
|
yield ctx.call_activity(hello_act, input=10)
|
||||||
yield ctx.wait_for_external_event("event1")
|
yield ctx.call_activity(hello_retryable_act, retry_policy=retry_policy)
|
||||||
|
yield ctx.call_child_workflow(child_retryable_wf, retry_policy=retry_policy)
|
||||||
|
|
||||||
|
# Change in event handling: Use when_any to handle both event and timeout
|
||||||
|
event = ctx.wait_for_external_event(event_name)
|
||||||
|
timeout = ctx.create_timer(timedelta(seconds=30))
|
||||||
|
winner = yield when_any([event, timeout])
|
||||||
|
|
||||||
|
if winner == timeout:
|
||||||
|
print('Workflow timed out waiting for event')
|
||||||
|
return 'Timeout'
|
||||||
|
|
||||||
yield ctx.call_activity(hello_act, input=100)
|
yield ctx.call_activity(hello_act, input=100)
|
||||||
yield ctx.call_activity(hello_act, input=1000)
|
yield ctx.call_activity(hello_act, input=1000)
|
||||||
|
return 'Completed'
|
||||||
```
|
```
|
||||||
|
|
||||||
[See the `hello_world_wf` workflow in context.](https://github.com/dapr/python-sdk/blob/master/examples/demo_workflow/app.py#LL32C1-L38C51)
|
[See the `hello_world_wf` workflow in context.](https://github.com/dapr/python-sdk/blob/main/examples/workflow/simple.py)
|
||||||
|
|
||||||
|
|
||||||
{{% /codetab %}}
|
{{% /codetab %}}
|
||||||
|
|
@ -405,89 +419,177 @@ Finally, compose the application using the workflow.
|
||||||
|
|
||||||
<!--python-->
|
<!--python-->
|
||||||
|
|
||||||
[In the following example](https://github.com/dapr/python-sdk/blob/master/examples/demo_workflow/app.py), for a basic Python hello world application using the Python SDK, your project code would include:
|
[In the following example](https://github.com/dapr/python-sdk/blob/main/examples/workflow/simple.py), for a basic Python hello world application using the Python SDK, your project code would include:
|
||||||
|
|
||||||
- A Python package called `DaprClient` to receive the Python SDK capabilities.
|
- A Python package called `DaprClient` to receive the Python SDK capabilities.
|
||||||
- A builder with extensions called:
|
- A builder with extensions called:
|
||||||
- `WorkflowRuntime`: Allows you to register workflows and workflow activities
|
- `WorkflowRuntime`: Allows you to register the workflow runtime.
|
||||||
- `DaprWorkflowContext`: Allows you to [create workflows]({{< ref "#write-the-workflow" >}})
|
- `DaprWorkflowContext`: Allows you to [create workflows]({{< ref "#write-the-workflow" >}})
|
||||||
- `WorkflowActivityContext`: Allows you to [create workflow activities]({{< ref "#write-the-workflow-activities" >}})
|
- `WorkflowActivityContext`: Allows you to [create workflow activities]({{< ref "#write-the-workflow-activities" >}})
|
||||||
- API calls. In the example below, these calls start, pause, resume, purge, and terminate the workflow.
|
- API calls. In the example below, these calls start, pause, resume, purge, and completing the workflow.
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from dapr.ext.workflow import WorkflowRuntime, DaprWorkflowContext, WorkflowActivityContext
|
from datetime import timedelta
|
||||||
from dapr.clients import DaprClient
|
from time import sleep
|
||||||
|
from dapr.ext.workflow import (
|
||||||
|
WorkflowRuntime,
|
||||||
|
DaprWorkflowContext,
|
||||||
|
WorkflowActivityContext,
|
||||||
|
RetryPolicy,
|
||||||
|
DaprWorkflowClient,
|
||||||
|
when_any,
|
||||||
|
)
|
||||||
|
from dapr.conf import Settings
|
||||||
|
from dapr.clients.exceptions import DaprInternalError
|
||||||
|
|
||||||
|
settings = Settings()
|
||||||
|
|
||||||
|
counter = 0
|
||||||
|
retry_count = 0
|
||||||
|
child_orchestrator_count = 0
|
||||||
|
child_orchestrator_string = ''
|
||||||
|
child_act_retry_count = 0
|
||||||
|
instance_id = 'exampleInstanceID'
|
||||||
|
child_instance_id = 'childInstanceID'
|
||||||
|
workflow_name = 'hello_world_wf'
|
||||||
|
child_workflow_name = 'child_wf'
|
||||||
|
input_data = 'Hi Counter!'
|
||||||
|
event_name = 'event1'
|
||||||
|
event_data = 'eventData'
|
||||||
|
non_existent_id_error = 'no such instance exists'
|
||||||
|
|
||||||
|
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),
|
||||||
|
)
|
||||||
|
|
||||||
|
wfr = WorkflowRuntime()
|
||||||
|
|
||||||
|
|
||||||
|
@wfr.workflow(name='hello_world_wf')
|
||||||
|
def hello_world_wf(ctx: DaprWorkflowContext, wf_input):
|
||||||
|
print(f'{wf_input}')
|
||||||
|
yield ctx.call_activity(hello_act, input=1)
|
||||||
|
yield ctx.call_activity(hello_act, input=10)
|
||||||
|
yield ctx.call_activity(hello_retryable_act, retry_policy=retry_policy)
|
||||||
|
yield ctx.call_child_workflow(child_retryable_wf, retry_policy=retry_policy)
|
||||||
|
|
||||||
|
# Change in event handling: Use when_any to handle both event and timeout
|
||||||
|
event = ctx.wait_for_external_event(event_name)
|
||||||
|
timeout = ctx.create_timer(timedelta(seconds=30))
|
||||||
|
winner = yield when_any([event, timeout])
|
||||||
|
|
||||||
|
if winner == timeout:
|
||||||
|
print('Workflow timed out waiting for event')
|
||||||
|
return 'Timeout'
|
||||||
|
|
||||||
|
yield ctx.call_activity(hello_act, input=100)
|
||||||
|
yield ctx.call_activity(hello_act, input=1000)
|
||||||
|
return 'Completed'
|
||||||
|
|
||||||
|
|
||||||
|
@wfr.activity(name='hello_act')
|
||||||
|
def hello_act(ctx: WorkflowActivityContext, wf_input):
|
||||||
|
global counter
|
||||||
|
counter += wf_input
|
||||||
|
print(f'New counter value is: {counter}!', flush=True)
|
||||||
|
|
||||||
|
|
||||||
|
@wfr.activity(name='hello_retryable_act')
|
||||||
|
def hello_retryable_act(ctx: WorkflowActivityContext):
|
||||||
|
global retry_count
|
||||||
|
if (retry_count % 2) == 0:
|
||||||
|
print(f'Retry count value is: {retry_count}!', flush=True)
|
||||||
|
retry_count += 1
|
||||||
|
raise ValueError('Retryable Error')
|
||||||
|
print(f'Retry count value is: {retry_count}! This print statement verifies retry', flush=True)
|
||||||
|
retry_count += 1
|
||||||
|
|
||||||
|
|
||||||
|
@wfr.workflow(name='child_retryable_wf')
|
||||||
|
def child_retryable_wf(ctx: DaprWorkflowContext):
|
||||||
|
global child_orchestrator_string, child_orchestrator_count
|
||||||
|
if not ctx.is_replaying:
|
||||||
|
child_orchestrator_count += 1
|
||||||
|
print(f'Appending {child_orchestrator_count} to child_orchestrator_string!', flush=True)
|
||||||
|
child_orchestrator_string += str(child_orchestrator_count)
|
||||||
|
yield ctx.call_activity(
|
||||||
|
act_for_child_wf, input=child_orchestrator_count, retry_policy=retry_policy
|
||||||
|
)
|
||||||
|
if child_orchestrator_count < 3:
|
||||||
|
raise ValueError('Retryable Error')
|
||||||
|
|
||||||
|
|
||||||
|
@wfr.activity(name='act_for_child_wf')
|
||||||
|
def act_for_child_wf(ctx: WorkflowActivityContext, inp):
|
||||||
|
global child_orchestrator_string, child_act_retry_count
|
||||||
|
inp_char = chr(96 + inp)
|
||||||
|
print(f'Appending {inp_char} to child_orchestrator_string!', flush=True)
|
||||||
|
child_orchestrator_string += inp_char
|
||||||
|
if child_act_retry_count % 2 == 0:
|
||||||
|
child_act_retry_count += 1
|
||||||
|
raise ValueError('Retryable Error')
|
||||||
|
child_act_retry_count += 1
|
||||||
|
|
||||||
# ...
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
with DaprClient() as d:
|
wfr.start()
|
||||||
host = settings.DAPR_RUNTIME_HOST
|
wf_client = DaprWorkflowClient()
|
||||||
port = settings.DAPR_GRPC_PORT
|
|
||||||
workflowRuntime = WorkflowRuntime(host, port)
|
|
||||||
workflowRuntime = WorkflowRuntime()
|
|
||||||
workflowRuntime.register_workflow(hello_world_wf)
|
|
||||||
workflowRuntime.register_activity(hello_act)
|
|
||||||
workflowRuntime.start()
|
|
||||||
|
|
||||||
# Start workflow
|
print('==========Start Counter Increase as per Input:==========')
|
||||||
print("==========Start Counter Increase as per Input:==========")
|
wf_client.schedule_new_workflow(
|
||||||
start_resp = d.start_workflow(instance_id=instanceId, workflow_component=workflowComponent,
|
workflow=hello_world_wf, input=input_data, instance_id=instance_id
|
||||||
workflow_name=workflowName, input=inputData, workflow_options=workflowOptions)
|
)
|
||||||
print(f"start_resp {start_resp.instance_id}")
|
|
||||||
|
|
||||||
# ...
|
wf_client.wait_for_workflow_start(instance_id)
|
||||||
|
|
||||||
# Pause workflow
|
# Sleep to let the workflow run initial activities
|
||||||
d.pause_workflow(instance_id=instanceId, workflow_component=workflowComponent)
|
sleep(12)
|
||||||
getResponse = d.get_workflow(instance_id=instanceId, workflow_component=workflowComponent)
|
|
||||||
print(f"Get response from {workflowName} after pause call: {getResponse.runtime_status}")
|
|
||||||
|
|
||||||
# Resume workflow
|
assert counter == 11
|
||||||
d.resume_workflow(instance_id=instanceId, workflow_component=workflowComponent)
|
assert retry_count == 2
|
||||||
getResponse = d.get_workflow(instance_id=instanceId, workflow_component=workflowComponent)
|
assert child_orchestrator_string == '1aa2bb3cc'
|
||||||
print(f"Get response from {workflowName} after resume call: {getResponse.runtime_status}")
|
|
||||||
|
|
||||||
sleep(1)
|
# Pause Test
|
||||||
# Raise workflow
|
wf_client.pause_workflow(instance_id=instance_id)
|
||||||
d.raise_workflow_event(instance_id=instanceId, workflow_component=workflowComponent,
|
metadata = wf_client.get_workflow_state(instance_id=instance_id)
|
||||||
event_name=eventName, event_data=eventData)
|
print(f'Get response from {workflow_name} after pause call: {metadata.runtime_status.name}')
|
||||||
|
|
||||||
sleep(5)
|
# Resume Test
|
||||||
# Purge workflow
|
wf_client.resume_workflow(instance_id=instance_id)
|
||||||
d.purge_workflow(instance_id=instanceId, workflow_component=workflowComponent)
|
metadata = wf_client.get_workflow_state(instance_id=instance_id)
|
||||||
|
print(f'Get response from {workflow_name} after resume call: {metadata.runtime_status.name}')
|
||||||
|
|
||||||
|
sleep(2) # Give the workflow time to reach the event wait state
|
||||||
|
wf_client.raise_workflow_event(instance_id=instance_id, event_name=event_name, data=event_data)
|
||||||
|
|
||||||
|
print('========= Waiting for Workflow completion', flush=True)
|
||||||
try:
|
try:
|
||||||
getResponse = d.get_workflow(instance_id=instanceId, workflow_component=workflowComponent)
|
state = wf_client.wait_for_workflow_completion(instance_id, timeout_in_seconds=30)
|
||||||
except DaprInternalError as err:
|
if state.runtime_status.name == 'COMPLETED':
|
||||||
if nonExistentIDError in err._message:
|
print('Workflow completed! Result: {}'.format(state.serialized_output.strip('"')))
|
||||||
print("Instance Successfully Purged")
|
else:
|
||||||
|
print(f'Workflow failed! Status: {state.runtime_status.name}')
|
||||||
|
except TimeoutError:
|
||||||
|
print('*** Workflow timed out!')
|
||||||
|
|
||||||
# Kick off another workflow for termination purposes
|
wf_client.purge_workflow(instance_id=instance_id)
|
||||||
start_resp = d.start_workflow(instance_id=instanceId, workflow_component=workflowComponent,
|
|
||||||
workflow_name=workflowName, input=inputData, workflow_options=workflowOptions)
|
|
||||||
print(f"start_resp {start_resp.instance_id}")
|
|
||||||
|
|
||||||
# Terminate workflow
|
|
||||||
d.terminate_workflow(instance_id=instanceId, workflow_component=workflowComponent)
|
|
||||||
sleep(1)
|
|
||||||
getResponse = d.get_workflow(instance_id=instanceId, workflow_component=workflowComponent)
|
|
||||||
print(f"Get response from {workflowName} after terminate call: {getResponse.runtime_status}")
|
|
||||||
|
|
||||||
# Purge workflow
|
|
||||||
d.purge_workflow(instance_id=instanceId, workflow_component=workflowComponent)
|
|
||||||
try:
|
try:
|
||||||
getResponse = d.get_workflow(instance_id=instanceId, workflow_component=workflowComponent)
|
wf_client.get_workflow_state(instance_id=instance_id)
|
||||||
except DaprInternalError as err:
|
except DaprInternalError as err:
|
||||||
if nonExistentIDError in err._message:
|
if non_existent_id_error in err._message:
|
||||||
print("Instance Successfully Purged")
|
print('Instance Successfully Purged')
|
||||||
|
|
||||||
|
wfr.shutdown()
|
||||||
|
|
||||||
workflowRuntime.shutdown()
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
{{% /codetab %}}
|
{{% /codetab %}}
|
||||||
|
|
||||||
{{% codetab %}}
|
{{% codetab %}}
|
||||||
|
|
|
||||||
|
|
@ -14,13 +14,13 @@ Now that you've [authored the workflow and its activities in your application]({
|
||||||
{{% codetab %}}
|
{{% codetab %}}
|
||||||
|
|
||||||
Manage your workflow within your code. In the workflow example from the [Author a workflow]({{< ref "howto-author-workflow.md#write-the-application" >}}) guide, the workflow is registered in the code using the following APIs:
|
Manage your workflow within your code. In the workflow example from the [Author a workflow]({{< ref "howto-author-workflow.md#write-the-application" >}}) guide, the workflow is registered in the code using the following APIs:
|
||||||
- **start_workflow**: Start an instance of a workflow
|
- **schedule_new_workflow**: Start an instance of a workflow
|
||||||
- **get_workflow**: Get information on the status of the workflow
|
- **get_workflow_state**: Get information on the status of the workflow
|
||||||
- **pause_workflow**: Pauses or suspends a workflow instance that can later be resumed
|
- **pause_workflow**: Pauses or suspends a workflow instance that can later be resumed
|
||||||
- **resume_workflow**: Resumes a paused workflow instance
|
- **resume_workflow**: Resumes a paused workflow instance
|
||||||
- **raise_workflow_event**: Raise an event on a workflow
|
- **raise_workflow_event**: Raise an event on a workflow
|
||||||
- **purge_workflow**: Removes all metadata related to a specific workflow instance
|
- **purge_workflow**: Removes all metadata related to a specific workflow instance
|
||||||
- **terminate_workflow**: Terminate or stop a particular instance of a workflow
|
- **wait_for_workflow_completion**: Complete a particular instance of a workflow
|
||||||
|
|
||||||
```python
|
```python
|
||||||
from dapr.ext.workflow import WorkflowRuntime, DaprWorkflowContext, WorkflowActivityContext
|
from dapr.ext.workflow import WorkflowRuntime, DaprWorkflowContext, WorkflowActivityContext
|
||||||
|
|
@ -34,27 +34,28 @@ eventName = "event1"
|
||||||
eventData = "eventData"
|
eventData = "eventData"
|
||||||
|
|
||||||
# Start the workflow
|
# Start the workflow
|
||||||
start_resp = d.start_workflow(instance_id=instanceId, workflow_component=workflowComponent,
|
wf_client.schedule_new_workflow(
|
||||||
workflow_name=workflowName, input=inputData, workflow_options=workflowOptions)
|
workflow=hello_world_wf, input=input_data, instance_id=instance_id
|
||||||
|
)
|
||||||
|
|
||||||
# Get info on the workflow
|
# Get info on the workflow
|
||||||
getResponse = d.get_workflow(instance_id=instanceId, workflow_component=workflowComponent)
|
wf_client.get_workflow_state(instance_id=instance_id)
|
||||||
|
|
||||||
# Pause the workflow
|
# Pause the workflow
|
||||||
d.pause_workflow(instance_id=instanceId, workflow_component=workflowComponent)
|
wf_client.pause_workflow(instance_id=instance_id)
|
||||||
|
metadata = wf_client.get_workflow_state(instance_id=instance_id)
|
||||||
|
|
||||||
# Resume the workflow
|
# Resume the workflow
|
||||||
d.resume_workflow(instance_id=instanceId, workflow_component=workflowComponent)
|
wf_client.resume_workflow(instance_id=instance_id)
|
||||||
|
|
||||||
# Raise an event on the workflow.
|
# Raise an event on the workflow.
|
||||||
d.raise_workflow_event(instance_id=instanceId, workflow_component=workflowComponent,
|
wf_client.raise_workflow_event(instance_id=instance_id, event_name=event_name, data=event_data)
|
||||||
event_name=eventName, event_data=eventData)
|
|
||||||
|
|
||||||
# Purge the workflow
|
# Purge the workflow
|
||||||
d.purge_workflow(instance_id=instanceId, workflow_component=workflowComponent)
|
wf_client.purge_workflow(instance_id=instance_id)
|
||||||
|
|
||||||
# Terminate the workflow
|
# Wait for workflow completion
|
||||||
d.terminate_workflow(instance_id=instanceId, workflow_component=workflowComponent)
|
wf_client.wait_for_workflow_completion(instance_id, timeout_in_seconds=30)
|
||||||
```
|
```
|
||||||
|
|
||||||
{{% /codetab %}}
|
{{% /codetab %}}
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ For this example, you will need:
|
||||||
<!-- IGNORE_LINKS -->
|
<!-- IGNORE_LINKS -->
|
||||||
- [Docker Desktop](https://www.docker.com/products/docker-desktop)
|
- [Docker Desktop](https://www.docker.com/products/docker-desktop)
|
||||||
<!-- END_IGNORE -->
|
<!-- END_IGNORE -->
|
||||||
- [.NET 6](https://dotnet.microsoft.com/download/dotnet/6.0), [.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0) or [.NET 9](https://dotnet.microsoft.com/download/dotnet/9.0) installed
|
- [.NET 8](https://dotnet.microsoft.com/download/dotnet/8.0) installed
|
||||||
|
|
||||||
**NOTE:** .NET 6 is the minimally supported version of .NET for the Dapr .NET SDK packages in this release. Only .NET 8 and .NET 9
|
**NOTE:** .NET 6 is the minimally supported version of .NET for the Dapr .NET SDK packages in this release. Only .NET 8 and .NET 9
|
||||||
will be supported in Dapr v1.16 and later releases.
|
will be supported in Dapr v1.16 and later releases.
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ description: Get started with the Dapr conversation building block
|
||||||
The conversation building block is currently in **alpha**.
|
The conversation building block is currently in **alpha**.
|
||||||
{{% /alert %}}
|
{{% /alert %}}
|
||||||
|
|
||||||
Let's take a look at how the [Dapr conversation building block]({{< ref conversation-overview.md >}}) makes interacting with Large Language Models (LLMs) easier. In this quickstart, you use the echo component to communicate with the mock LLM and ask it for a poem about Dapr.
|
Let's take a look at how the [Dapr conversation building block]({{< ref conversation-overview.md >}}) makes interacting with Large Language Models (LLMs) easier. In this quickstart, you use the echo component to communicate with the mock LLM and ask it to define Dapr.
|
||||||
|
|
||||||
You can try out this conversation quickstart by either:
|
You can try out this conversation quickstart by either:
|
||||||
|
|
||||||
|
|
@ -18,7 +18,7 @@ You can try out this conversation quickstart by either:
|
||||||
- [Running the application without the template]({{< ref "#run-the-app-without-the-template" >}})
|
- [Running the application without the template]({{< ref "#run-the-app-without-the-template" >}})
|
||||||
|
|
||||||
{{% alert title="Note" color="primary" %}}
|
{{% alert title="Note" color="primary" %}}
|
||||||
Currently, only the HTTP quickstart sample is available in Python and JavaScript.
|
Currently, you can only use JavaScript for the quickstart sample using HTTP, not the JavaScript SDK.
|
||||||
{{% /alert %}}
|
{{% /alert %}}
|
||||||
|
|
||||||
## Run the app with the template file
|
## Run the app with the template file
|
||||||
|
|
@ -50,7 +50,7 @@ git clone https://github.com/dapr/quickstarts.git
|
||||||
From the root of the Quickstarts directory, navigate into the conversation directory:
|
From the root of the Quickstarts directory, navigate into the conversation directory:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd conversation/python/http/conversation
|
cd conversation/python/sdk/conversation
|
||||||
```
|
```
|
||||||
|
|
||||||
Install the dependencies:
|
Install the dependencies:
|
||||||
|
|
@ -61,7 +61,7 @@ pip3 install -r requirements.txt
|
||||||
|
|
||||||
### Step 3: Launch the conversation service
|
### Step 3: Launch the conversation service
|
||||||
|
|
||||||
Navigate back to the `http` directory and start the conversation service with the following command:
|
Navigate back to the `sdk` directory and start the conversation service with the following command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dapr run -f .
|
dapr run -f .
|
||||||
|
|
@ -117,37 +117,28 @@ In the application code:
|
||||||
- The mock LLM echoes "What is dapr?".
|
- The mock LLM echoes "What is dapr?".
|
||||||
|
|
||||||
```python
|
```python
|
||||||
import logging
|
from dapr.clients import DaprClient
|
||||||
import requests
|
from dapr.clients.grpc._request import ConversationInput
|
||||||
import os
|
|
||||||
|
|
||||||
logging.basicConfig(level=logging.INFO)
|
with DaprClient() as d:
|
||||||
|
inputs = [
|
||||||
|
ConversationInput(content="What is dapr?", role='user', scrub_pii=True),
|
||||||
|
]
|
||||||
|
|
||||||
base_url = os.getenv('BASE_URL', 'http://localhost') + ':' + os.getenv(
|
metadata = {
|
||||||
'DAPR_HTTP_PORT', '3500')
|
'model': 'modelname',
|
||||||
|
'key': 'authKey',
|
||||||
CONVERSATION_COMPONENT_NAME = 'echo'
|
'cacheTTL': '10m',
|
||||||
|
|
||||||
input = {
|
|
||||||
'name': 'echo',
|
|
||||||
'inputs': [{'message':'What is dapr?'}],
|
|
||||||
'parameters': {},
|
|
||||||
'metadata': {}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Send input to conversation endpoint
|
print('Input sent: What is dapr?')
|
||||||
result = requests.post(
|
|
||||||
url='%s/v1.0-alpha1/conversation/%s/converse' % (base_url, CONVERSATION_COMPONENT_NAME),
|
|
||||||
json=input
|
|
||||||
)
|
|
||||||
|
|
||||||
logging.info('Input sent: What is dapr?')
|
response = d.converse_alpha1(
|
||||||
|
name='echo', inputs=inputs, temperature=0.7, context_id='chat-123', metadata=metadata
|
||||||
|
)
|
||||||
|
|
||||||
# Parse conversation output
|
for output in response.outputs:
|
||||||
data = result.json()
|
print(f'Output response: {output.result}')
|
||||||
output = data["outputs"][0]["result"]
|
|
||||||
|
|
||||||
logging.info('Output response: ' + output)
|
|
||||||
```
|
```
|
||||||
|
|
||||||
{{% /codetab %}}
|
{{% /codetab %}}
|
||||||
|
|
@ -575,7 +566,7 @@ git clone https://github.com/dapr/quickstarts.git
|
||||||
From the root of the Quickstarts directory, navigate into the conversation directory:
|
From the root of the Quickstarts directory, navigate into the conversation directory:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
cd conversation/python/http/conversation
|
cd conversation/python/sdk/conversation
|
||||||
```
|
```
|
||||||
|
|
||||||
Install the dependencies:
|
Install the dependencies:
|
||||||
|
|
@ -586,7 +577,7 @@ pip3 install -r requirements.txt
|
||||||
|
|
||||||
### Step 3: Launch the conversation service
|
### Step 3: Launch the conversation service
|
||||||
|
|
||||||
Navigate back to the `http` directory and start the conversation service with the following command:
|
Navigate back to the `sdk` directory and start the conversation service with the following command:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
dapr run --app-id conversation --resources-path ../../../components -- python3 app.py
|
dapr run --app-id conversation --resources-path ../../../components -- python3 app.py
|
||||||
|
|
|
||||||
|
|
@ -251,7 +251,6 @@ class WorkflowConsoleApp:
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
app = WorkflowConsoleApp()
|
app = WorkflowConsoleApp()
|
||||||
app.main()
|
app.main()
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
#### `order-processor/workflow.py`
|
#### `order-processor/workflow.py`
|
||||||
|
|
@ -276,7 +275,6 @@ wfr = WorkflowRuntime()
|
||||||
|
|
||||||
logging.basicConfig(level=logging.INFO)
|
logging.basicConfig(level=logging.INFO)
|
||||||
|
|
||||||
|
|
||||||
@wfr.workflow(name="order_processing_workflow")
|
@wfr.workflow(name="order_processing_workflow")
|
||||||
def order_processing_workflow(ctx: DaprWorkflowContext, order_payload_str: str):
|
def order_processing_workflow(ctx: DaprWorkflowContext, order_payload_str: str):
|
||||||
"""Defines the order processing workflow.
|
"""Defines the order processing workflow.
|
||||||
|
|
@ -343,7 +341,6 @@ def notify_activity(ctx: WorkflowActivityContext, input: Notification):
|
||||||
logger = logging.getLogger('NotifyActivity')
|
logger = logging.getLogger('NotifyActivity')
|
||||||
logger.info(input.message)
|
logger.info(input.message)
|
||||||
|
|
||||||
|
|
||||||
@wfr.activity(name="process_payment_activity")
|
@wfr.activity(name="process_payment_activity")
|
||||||
def process_payment_activity(ctx: WorkflowActivityContext, input: PaymentRequest):
|
def process_payment_activity(ctx: WorkflowActivityContext, input: PaymentRequest):
|
||||||
"""Defines Process Payment Activity.This is used by the workflow to process a payment"""
|
"""Defines Process Payment Activity.This is used by the workflow to process a payment"""
|
||||||
|
|
@ -353,7 +350,6 @@ def process_payment_activity(ctx: WorkflowActivityContext, input: PaymentRequest
|
||||||
+' USD')
|
+' USD')
|
||||||
logger.info(f'Payment for request ID {input.request_id} processed successfully')
|
logger.info(f'Payment for request ID {input.request_id} processed successfully')
|
||||||
|
|
||||||
|
|
||||||
@wfr.activity(name="verify_inventory_activity")
|
@wfr.activity(name="verify_inventory_activity")
|
||||||
def verify_inventory_activity(ctx: WorkflowActivityContext,
|
def verify_inventory_activity(ctx: WorkflowActivityContext,
|
||||||
input: InventoryRequest) -> InventoryResult:
|
input: InventoryRequest) -> InventoryResult:
|
||||||
|
|
@ -377,8 +373,6 @@ def verify_inventory_activity(ctx: WorkflowActivityContext,
|
||||||
return InventoryResult(True, inventory_item)
|
return InventoryResult(True, inventory_item)
|
||||||
return InventoryResult(False, None)
|
return InventoryResult(False, None)
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@wfr.activity(name="update_inventory_activity")
|
@wfr.activity(name="update_inventory_activity")
|
||||||
def update_inventory_activity(ctx: WorkflowActivityContext,
|
def update_inventory_activity(ctx: WorkflowActivityContext,
|
||||||
input: PaymentRequest) -> InventoryResult:
|
input: PaymentRequest) -> InventoryResult:
|
||||||
|
|
@ -401,8 +395,6 @@ def update_inventory_activity(ctx: WorkflowActivityContext,
|
||||||
client.save_state(store_name, input.item_being_purchased, new_val)
|
client.save_state(store_name, input.item_being_purchased, new_val)
|
||||||
logger.info(f'There are now {new_quantity} {input.item_being_purchased} left in stock')
|
logger.info(f'There are now {new_quantity} {input.item_being_purchased} left in stock')
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@wfr.activity(name="request_approval_activity")
|
@wfr.activity(name="request_approval_activity")
|
||||||
def request_approval_activity(ctx: WorkflowActivityContext,
|
def request_approval_activity(ctx: WorkflowActivityContext,
|
||||||
input: OrderPayload):
|
input: OrderPayload):
|
||||||
|
|
@ -413,7 +405,6 @@ def request_approval_activity(ctx: WorkflowActivityContext,
|
||||||
|
|
||||||
logger.info('Requesting approval for payment of '+f'{input["total_cost"]}'+' USD for '
|
logger.info('Requesting approval for payment of '+f'{input["total_cost"]}'+' USD for '
|
||||||
+f'{input["quantity"]}' +' ' +f'{input["item_name"]}')
|
+f'{input["quantity"]}' +' ' +f'{input["item_name"]}')
|
||||||
|
|
||||||
```
|
```
|
||||||
{{% /codetab %}}
|
{{% /codetab %}}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,8 +7,8 @@ description: "Define secret scopes by augmenting the existing configuration reso
|
||||||
description: "Define secret scopes by augmenting the existing configuration resource with restrictive permissions."
|
description: "Define secret scopes by augmenting the existing configuration resource with restrictive permissions."
|
||||||
---
|
---
|
||||||
|
|
||||||
In addition to [scoping which applications can access a given component]({{< ref "component-scopes.md">}}), you can also scop a named secret store component to one or more secrets for an application. By defining `allowedSecrets` and/or `deniedSecrets` lists, you restrict applications to access only specific secrets.
|
In addition to [scoping which applications can access a given component]({{< ref "component-scopes.md">}}), you can also scope a named secret store component to one or more secrets for an application. By defining `allowedSecrets` and/or `deniedSecrets` lists, you restrict applications to access only specific secrets.
|
||||||
In addition to [scoping which applications can access a given component]({{< ref "component-scopes.md">}}), you can also scop a named secret store component to one or more secrets for an application. By defining `allowedSecrets` and/or `deniedSecrets` lists, you restrict applications to access only specific secrets.
|
In addition to [scoping which applications can access a given component]({{< ref "component-scopes.md">}}), you can also scope a named secret store component to one or more secrets for an application. By defining `allowedSecrets` and/or `deniedSecrets` lists, you restrict applications to access only specific secrets.
|
||||||
|
|
||||||
For more information about configuring a Configuration resource:
|
For more information about configuring a Configuration resource:
|
||||||
- [Configuration overview]({{< ref configuration-overview.md >}})
|
- [Configuration overview]({{< ref configuration-overview.md >}})
|
||||||
|
|
|
||||||
|
|
@ -123,6 +123,7 @@ services:
|
||||||
"--app-id", "nodeapp",
|
"--app-id", "nodeapp",
|
||||||
"--app-port", "3000",
|
"--app-port", "3000",
|
||||||
"--placement-host-address", "placement:50006", # Dapr's placement service can be reach via the docker DNS entry
|
"--placement-host-address", "placement:50006", # Dapr's placement service can be reach via the docker DNS entry
|
||||||
|
"--scheduler-host-address", "scheduler:50007", # Dapr's scheduler service can be reach via the docker DNS entry
|
||||||
"--resources-path", "./components"
|
"--resources-path", "./components"
|
||||||
]
|
]
|
||||||
volumes:
|
volumes:
|
||||||
|
|
@ -134,22 +135,19 @@ services:
|
||||||
... # Deploy other daprized services and components (i.e. Redis)
|
... # Deploy other daprized services and components (i.e. Redis)
|
||||||
|
|
||||||
placement:
|
placement:
|
||||||
image: "daprio/dapr"
|
image: "daprio/placement"
|
||||||
command: ["./placement", "--port", "50006"]
|
command: ["./placement", "--port", "50006"]
|
||||||
ports:
|
ports:
|
||||||
- "50006:50006"
|
- "50006:50006"
|
||||||
|
|
||||||
scheduler:
|
scheduler:
|
||||||
image: "daprio/dapr"
|
image: "daprio/scheduler"
|
||||||
command: ["./scheduler", "--port", "50007"]
|
command: ["./scheduler", "--port", "50007", "--etcd-data-dir", "/data"]
|
||||||
ports:
|
ports:
|
||||||
- "50007:50007"
|
- "50007:50007"
|
||||||
# WARNING - This is a tmpfs volume, your state will not be persisted across restarts
|
user: root
|
||||||
volumes:
|
volumes:
|
||||||
- type: tmpfs
|
- "./dapr-etcd-data/:/data"
|
||||||
target: /data
|
|
||||||
tmpfs:
|
|
||||||
size: "64m"
|
|
||||||
|
|
||||||
networks:
|
networks:
|
||||||
hello-dapr: null
|
hello-dapr: null
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue