dapr / components-contrib

Community driven, reusable components for distributed apps
Apache License 2.0
546 stars 477 forks source link

MongoDB as an actor state store does not work #2351

Closed danielgerlag closed 1 year ago

danielgerlag commented 1 year ago

If I used Redis as my actor state store, it works fine, but if I switch to Mongo, then as soon as an actor tries to persist state, the app crashes and I see this error:

Error: {"errorCode":"ERR_ACTOR_STATE_TRANSACTION_SAVE","message":"error saving actor transaction state: error during transaction, aborting the transaction: (IllegalOperation) Transaction numbers are only allowed on a replica set member or mongos"}

Is there a special way you need to configure Mongo for actors that is not documented?

jaceks2106 commented 1 year ago

Hello,

Any update on this? Problem still occurs.

ItalyPaleAle commented 1 year ago

How are you spinning up MongoDB?

jaceks2106 commented 1 year ago

How are you spinning up MongoDB?

FYI, I am using dapr with Tye.

Tye definition:

name: example-app
extensions:
- name: dapr
  components-path: ./dapr/components

services:

  - name: example-db
    image: mongo
    bindings:
      - port: 27017
    volumes:
      - name: example-db
        target: /data/db
      - source: ./env_files/mongodb_runfiles
        target: /docker-entrypoint-initdb.d
    env_file:
      - ./env_files/mongodb.env

./dapr/components

apiVersion: dapr.io/v1alpha1
kind: Component

metadata:
  name: example-statestore

spec:
  type: state.mongodb
  version: v1
  metadata:
  - name: host
    value: "localhost:27017"
  - name: username
    value: "example"
  - name: password
    value: "example_password"
  - name: databaseName
    value: "example"
  - name: params
    value: "?authSource=example"
  - name: operationTimeout
    value: "60s"
  - name: readConcern
    value: "local"
  - name: writeConcern
    value: 0

  - name: actorStateStore
    value: "true"

scopes:
- example

./env_files/mongodb.env

MONGO_INITDB_ROOT_USERNAME=admin
MONGO_INITDB_ROOT_PASSWORD=password
MONGO_INITDB_DATABASE=admin

./env_files/mongodb_runfiles - mongo-init.js

const dbName = 'example'
const collection = 'daprCollection'

db = db.getSiblingDB(dbName)

db.createUser(
        {
            user: "example",
            pwd: "example_password",
            roles: [
                {
                    role: "readWrite",
                    db: "example"
                }
            ]
        }
);

db.createCollection(collection);
jaceks2106 commented 1 year ago

And this is the error:

[example_9073c3a7-1]: {"@t":"2023-01-27T17:39:01.7152743Z","@m":"Connection id \"\"0HMO0HKU9CBOP\"\", Request id \"\"0HMO0HKU9CBOP:00000002\"\": An unhandled exception was thrown by the application.","@i":"560e7d32","@l":"Error","@x":"Dapr.Actors.ActorMethodInvocationException: Remote Actor Method Exception, DETAILS: Exception: DaprApiException, Method Name: MoveNext, Line Number: 0, Exception uuid: 6967fb9b-a77f-4296-a1bb-4318244db553\r\n ---> Dapr.Actors.ActorInvokeException: error saving actor transaction state: error during transaction, aborting the transaction: (IllegalOperation) Transaction numbers are only allowed on a replica set member or mongos\r\n --- End of inner exception stack trace ---\r\n at Dapr.Actors.DaprHttpInteractor.InvokeActorMethodWithRemotingAsync(ActorMessageSerializersManager serializersManager, IActorRequestMessage remotingRequestRequestMessage, CancellationToken cancellationToken)\r\n at Dapr.Actors.Communication.Client.ActorRemotingClient.InvokeAsync(IActorRequestMessage remotingRequestMessage, CancellationToken cancellationToken)\r\n at Dapr.Actors.Client.ActorProxy.InvokeMethodAsync(Int32 interfaceId, Int32 methodId, String methodName, IActorRequestMessageBody requestMsgBodyValue, CancellationToken cancellationToken)\r\

berndverst commented 1 year ago

See this answer that explains it better than I could https://stackoverflow.com/questions/51461952/mongodb-v4-0-transaction-mongoerror-transaction-numbers-are-only-allowed-on-a

MongoDB Transactions (a required feature for actor state store) are only available with Mongo Replica Sets. So you must set up a replica set for Mongo DB. While we cannot give recommendations or production guidance for doing so, you can use the Docker file we use in our certification test:

https://github.com/dapr/components-contrib/blob/e4c55cbf4b05da33f74eccb1b018dd3992574f2f/tests/certification/state/mongodb/docker-compose-cluster.yml