Incorrect outbox metadata example for Python
Describe the issue
Example for outbox in python seems to be errored. It assumes we can, via python SDK, do:
await client.state.transaction(DAPR_STORE_NAME, ops);
but:
== APP == c.state.save(
== APP == AttributeError: 'DaprClient' object has no attribute 'state'
Indeed python SDK does not provide this state attribute.
So I tried:
c.save_state(
store_name=DAPR_STORE_NAME,
key="test",
value='{ "say": "hello world from outbox-metadata" }',
state_metadata={ "outbox.projection": "true" },
metadata=(("outbox.projection", "true"),)
)
But despite my efforts in injecting metadatas, I could not see any outbox message in my outbox topic.
Only way I found to get a message in outbox topic is to use transactions:
transaction_operation = TransactionalStateOperation(
operation_type=TransactionOperationType.upsert,
key="1",
data='{ "say": "hello world from outbox transaction" }',
)
c.execute_state_transaction(
store_name=DAPR_STORE_NAME,
operations=[transaction_operation],
transactional_metadata={ 'datacontenttype': 'application/json'},
metadata= (('datacontenttype', 'application/json'),)
)
I made this project where you can find full code and logs: https://github.com/jseguillon/dapr-outbox-python
URL of the docs
https://github.com/dapr/docs/blob/v1.14/daprdocs/content/en/developing-applications/building-blocks/state-management/howto-outbox.md?plain=1#L205
Expected content
A working Python example for outbox with metadata like example for others langages
Screenshots
metadata:
transaction:
Additional context
@jseguillon Appreciate you taking the time to raise this issue. Yes you are correct , the example is wrong. Can I suggest
- That the sample in docs https://docs.dapr.io/developing-applications/building-blocks/state-management/howto-outbox/#shape-the-outbox-pattern-message is updated with
@app.post('/state-outbox-transaction')
def outbox_transaction():
from dapr.clients.grpc._request import TransactionalStateOperation, TransactionOperationType, DaprRequest
transaction_operation = TransactionalStateOperation(
operation_type=TransactionOperationType.upsert,
key="1",
data='{ "say": "hello world from outbox transaction" }',
)
print("/state-outbox-transaction: Execute the state transaction")
c.execute_state_transaction(
store_name=DAPR_STORE_NAME,
operations=[transaction_operation],
transactional_metadata={ 'datacontenttype': 'application/json'},
metadata= (('datacontenttype', 'application/json'),)
)
print("/state-outbox-transaction: Transaction executed")
return JSONResponse(content={"success": "true"})
Have to update the code here https://docs.dapr.io/developing-applications/building-blocks/state-management/howto-outbox/#override-dapr-generated-cloudevent-fields also
Feel free to do a docs contribution is you like
- I raised this issue in the Python SDK repo https://github.com/dapr/python-sdk/issues/790 and it would be amazing it you could raise a PR contribution for this.
By configuring the state store, you can use the outbox pattern without any additional metadata in the requests. For example:
apiVersion: dapr.io/v1alpha1
kind: Component
metadata:
name: statestore
spec:
type: state.redis
version: v1
metadata:
- name: redisHost
value: localhost:6379
- name: redisPassword
value: ""
- name: actorStateStore
value: "true"
- name: outboxPublishPubsub
value: "pubsub". # This is the pubsub component name
- name: outboxPublishTopic
value: "test"
The additional metadata fields are needed to combine outbox and non-outbox messages on the same state store. Unfortunately, we currently don't support adding metadata for TransactionalStateOperation in the python-sdk, but I opened a PR here which will allow you to do something like:
from dapr.clients import DaprClient
from dapr.clients.grpc._request import TransactionalStateOperation, TransactionOperationType
DAPR_STORE_NAME = "statestore"
with DaprClient() as d:
d.execute_state_transaction(store_name=DAPR_STORE_NAME, operations=[
TransactionalStateOperation(key="key1", data="val1", metadata={"outbox.projection": "false"}),
TransactionalStateOperation(key="key1", data="val2", metadata={"outbox.projection": "true"}),
],)
print("Transaction with outbox pattern executed successfully!")
@elena-kolevska the doc was updated with 4913 and this issue can be closed. TY!