How to best troubleshoot what seems like a wiring problem?

This is a node service. Using recent codegen (in the SDK). I added a view.

Error reported from Akka system: AS-00407 No method can be found on service [com.example.UserPersistedSessionQueryService] to handle protobuf type of [json.akkaserverless.com/object] on input [value_entity: "user_persisted_sessions"].

To fix this either declare a method for this type, or declare a method that accepts `google.protobuf.Any` (accepted types are: com.example.domain.UserPersistedSessionState). See documentation: https://developer.lightbend.com/docs/akka-serverless/javascript/

At user_persisted_session_api.proto:60:5:
    rpc UpdateUser(com.example.domain.UserPersistedSessionState) returns (com.example.domain.UserPersistedSessionState) {
        option (akkaserverless.method).eventing.in = { 
            value_entity: "user_persisted_sessions"
          };
          option (akkaserverless.method).view.update = { 
            table: "user_sessions" 

          };
    };
^C

I assume that this is a protobuf problem:

// This is the public API offered by your entity.
syntax = "proto3";

import "google/protobuf/empty.proto";
import "google/protobuf/any.proto";
import "akkaserverless/annotations.proto";
import "google/api/annotations.proto";
import "user_persisted_session_domain.proto";

package com.example;

message UpdateUserPersistedSession {
    string user_persisted_session_id = 1 [(akkaserverless.field).entity_key = true];
    bool active = 2;
    com.example.domain.Profile profile = 3;
    com.example.domain.LastActivity lastActivity = 4;
    repeated com.example.domain.Recommendation recommendations  = 5;

}

message GetOnlineStatus {
    string user_persisted_session_id = 1 [(akkaserverless.field).entity_key = true];
}

message GetActivity {
    string user_persisted_session_id = 1 [(akkaserverless.field).entity_key = true];
}

message GetRecommendations {
    string user_persisted_session_id = 1 [(akkaserverless.field).entity_key = true];
}

message Recommendations {
    repeated com.example.domain.Recommendation recommendation = 1;
}

message OnlineStatus {
    bool active = 1;
}

message OnlineUsersRequest {}

message GetUsersRequest {}

service UserPersistedSessionService {
    option (akkaserverless.service) = {
        type : SERVICE_TYPE_ENTITY
        component : ".domain.UserPersistedSession"
    };

    rpc UpdateUser(UpdateUserPersistedSession) returns (google.protobuf.Empty);
    rpc GetOnlineStatusForUser(GetOnlineStatus) returns (OnlineStatus);
    rpc GetLastActivityForUser(GetActivity) returns (domain.LastActivity);
    rpc GetRecommendationsForUser(GetRecommendations) returns (Recommendations);

    
}

service UserPersistedSessionQueryService {
    rpc UpdateUser(com.example.domain.UserPersistedSessionState) returns (com.example.domain.UserPersistedSessionState) {
        option (akkaserverless.method).eventing.in = { 
            value_entity: "user_persisted_sessions"
          };
          option (akkaserverless.method).view.update = { 
            table: "user_sessions" 

          };
    };

    rpc GetUsers(GetUsersRequest) returns (stream com.example.domain.UserPersistedSessionState) { 
        option (akkaserverless.method).view.query = { 
          query: "SELECT * FROM user_sessions"
        };
    }

}

and

syntax = "proto3";

package com.example.domain;
import "akkaserverless/annotations.proto";


option (akkaserverless.file).value_entity = {
    name: "UserPersistedSession"
    entity_type: "user_persisted_sessions"
    state: "UserPersistedSessionState"
};

message UserPersistedSessionState {
    bool active = 1;
    Profile profile = 2;
    LastActivity lastActivity = 3;
    repeated Recommendation recommendations  = 4;
}

message Profile {
    int32 externalId = 1;
    string firstName = 2;
    string lastName = 3;
}

message LastActivity {
    enum Type {
        WEB = 0;
        MOBILE = 1;
        CHAT = 2;
    };
    Type type = 1;
    int64 timestamp = 2;
}

message Recommendation {
    int32 id = 1;
    string name = 2;
    string description = 3;
    string uri = 4;
}

Any ideas on where to start troubleshooting?

The AS-00407 error suggests your UserPersistedSessionQueryService received an incoming message of type json.akkaserverless.com/object. Since it should be getting state updates from your UserPersistedSessionService, which should have UserPersistedSession objects as its domain, this is surprising. I suspect this is actually a bug in the Akka Serverless proxy - or at least a lack of validation there. I’ll pass this on to the team.

Looks related to Error: Fallback to JSON serialization supported, but object does not define a type property. Where the value entity state is being serialized as JSON (with a type name of object ) and not as protobuf messages. For JSON events, the eventing system always sends these to the Any method for the subscribing service (they don’t match the protobuf messages). Receiving JSON messages is described for topic eventing, and will apply to value entity changes or event sourced entity events as well.

@jeremy.pollock, there should be two options:

You can continue working with JSON-based state. In the view, have a method that receives google.protobuf.Any messages, and uses transform_updates: true and a handler to transform the JSON state to the expected protobuf message, which the view will store. I think views currently require typed protobuf messages to work with, and there’s no support for JSON encoded state.

Alternatively, it will probably be easier to work with protobuf messages throughout. In the value entity, remove the serializeFallbackToJson option. Look up the protobuf message type:

const UserPersistedSessionState = entity.lookupType("com.example.domain.UserPersistedSessionState");

And then create a protobuf message object for your initial state:

entity.setInitial(entityId => UserPersistedSessionState.create());

You can also pass objects to the create method to set any values.

Described in the docs on using protobuf types and creating initial state.

You can continue to mutate the current state and then persist with updateState as before.

1 Like