Skip to content
This repository has been archived by the owner on Mar 16, 2022. It is now read-only.

WIP-CRUD on top of Event Sourcing #220

Merged
Merged
Show file tree
Hide file tree
Changes from 103 commits
Commits
Show all changes
129 commits
Select commit Hold shift + click to select a range
6d3b2c1
Issue-197: add npm task for preparing node-support to be able to buil…
ralphlaude Feb 22, 2020
0fbd706
Merge remote-tracking branch 'upstream/master'
ralphlaude Feb 24, 2020
27d22ff
Merge remote-tracking branch 'upstream/master'
ralphlaude Feb 27, 2020
2a32aa1
Merge remote-tracking branch 'upstream/master'
ralphlaude Mar 12, 2020
579d1c4
Merge remote-tracking branch 'upstream/master'
ralphlaude Mar 16, 2020
8014961
Merge remote-tracking branch 'upstream/master'
ralphlaude Mar 23, 2020
91f3333
Merge remote-tracking branch 'upstream/master'
ralphlaude Mar 25, 2020
38327d3
Proposal for CRUD on top of Event Sourcing
ralphlaude Mar 30, 2020
6cc25fe
Proposal for CRUD on top of Event Sourcing; Comment code handling events
ralphlaude Mar 30, 2020
9a7a8bf
rollback changes in the proxy and add proto file for the CRUD domain
ralphlaude Mar 30, 2020
db2e4a8
Add CrudEntity annotation. Add registration for CrudEntity in CloudSt…
ralphlaude Mar 31, 2020
8aa1e97
Merge remote-tracking branch 'upstream/master'
ralphlaude Apr 2, 2020
2374b7b
change CrudEntity annotation. Change registration for CrudEntity in C…
ralphlaude Apr 14, 2020
82c2377
Merge remote-tracking branch 'upstream/master'
ralphlaude Apr 16, 2020
1f741d9
Merge remote-tracking branch 'upstream/master'
ralphlaude Apr 21, 2020
ca6b416
Merge remote-tracking branch 'upstream/master'
ralphlaude Apr 23, 2020
92effcd
Merge remote-tracking branch 'upstream/master'
ralphlaude Apr 24, 2020
473d682
Merge remote-tracking branch 'upstream/master'
ralphlaude Apr 24, 2020
6e23140
Merge remote-tracking branch 'upstream/master'
ralphlaude Apr 26, 2020
3664944
Merge remote-tracking branch 'upstream/master'
ralphlaude Apr 28, 2020
c9cc5f6
Merge branch 'master' into wip-crud-on-top-of-event-sourcing
ralphlaude Apr 28, 2020
cee69f1
Merge remote-tracking branch 'upstream/master'
ralphlaude May 1, 2020
8e951e4
Merge remote-tracking branch 'upstream/master'
ralphlaude May 4, 2020
170bb0c
Merge branch 'master' into wip-crud-on-top-of-event-sourcing
ralphlaude May 4, 2020
78b7840
Initial version for the CRUD protocol and the implementation
ralphlaude May 14, 2020
012c1e3
remove unused import
ralphlaude May 14, 2020
5647e15
Merge remote-tracking branch 'upstream/master'
ralphlaude May 15, 2020
dc810c4
Add comments and change the proto definition
ralphlaude May 15, 2020
078517f
Change the protocol to have one reply type for all operations and imp…
ralphlaude May 18, 2020
5e8ec79
Merge remote-tracking branch 'upstream/master'
ralphlaude May 21, 2020
da4a331
add crud command type as proto field option and extend the user funct…
ralphlaude May 24, 2020
78345f8
add some documentation and do some small refactoring
ralphlaude May 25, 2020
d1bdbb1
add java doc for crud protocol. extend the shopping cart example. ref…
ralphlaude May 26, 2020
d9a5dbd
Merge remote-tracking branch 'upstream/master'
ralphlaude May 27, 2020
ab73109
Merge branch 'master' into wip-crud-on-top-of-event-sourcing
ralphlaude May 27, 2020
e906657
Merge branch 'prototype-crud-on-event-sourcing' into wip-crud-on-top-…
ralphlaude May 27, 2020
344d8d9
Documents the protocol and add new grpc type for command type. implem…
ralphlaude Jun 9, 2020
cda633a
Merge branch 'prototype-crud-on-event-sourcing' into wip-crud-on-top-…
ralphlaude Jun 9, 2020
87d1c4f
Merge branch 'master' into wip-crud-on-top-of-event-sourcing
ralphlaude Jul 14, 2020
d0215aa
Provide a definition of the protocol with snapshotting capabilities a…
ralphlaude Jul 14, 2020
9f72587
wording fixed
ralphlaude Jul 14, 2020
866941d
add sample for crud shopping cart and rollback the sample shopping ca…
ralphlaude Jul 26, 2020
6e997f2
remove old crud shopping cart
ralphlaude Jul 26, 2020
9c9e02b
add StreamFailed in the presstart method
ralphlaude Jul 27, 2020
164a650
add tests for crud entity
ralphlaude Jul 27, 2020
9a3cf53
removed obsolete classes
ralphlaude Jul 27, 2020
c5de37d
add annotations for update and delete handlers
ralphlaude Jul 28, 2020
0979a9e
fixed scala format
ralphlaude Jul 28, 2020
5169003
fixed unit value
ralphlaude Jul 28, 2020
b93a3c0
Merge branch 'master' into wip-crud-on-top-of-event-sourcing
ralphlaude Jul 28, 2020
1321d1e
fixed protobuf attribute index and fixed crud init state handling
ralphlaude Jul 29, 2020
c6e162a
fixed shopping cart entity
ralphlaude Jul 30, 2020
0675b17
call command handler only when the command was successful. Make the C…
ralphlaude Aug 26, 2020
1fd017d
Merge branch 'master' into wip-crud-on-top-of-event-sourcing
ralphlaude Aug 26, 2020
928933c
fixed test
ralphlaude Aug 26, 2020
2310fc9
add native CRUD support with slick and integrate the in memory CRUD s…
ralphlaude Sep 7, 2020
919756d
modified markdown
ralphlaude Sep 7, 2020
dd2e4c8
add generic to command context and entity handler
ralphlaude Sep 7, 2020
bbd5e53
remove the use of sequence number in the GRPC CRUD protocol
ralphlaude Sep 7, 2020
99f8ffc
remove event sourced in memory snapshot store. adapt log for in memor…
ralphlaude Sep 7, 2020
8692f57
first version for checking null on updateEntity
ralphlaude Sep 7, 2020
18ce9c8
add comments
ralphlaude Sep 7, 2020
209648d
add exception handling based on the one in event sourced
ralphlaude Sep 9, 2020
44175e0
add new lines
ralphlaude Sep 9, 2020
b866e71
rewrite crud protocol by using oly command handler and passing the st…
ralphlaude Sep 14, 2020
2731570
change entity initialization
ralphlaude Sep 15, 2020
46b54fc
change entity initialization and adapt annotation based support test
ralphlaude Sep 15, 2020
7ec4ab5
change test name
ralphlaude Sep 15, 2020
d076e86
ignore CRUD entity test
ralphlaude Sep 15, 2020
b05f7aa
remove subsequent invocation checking which is not needed
ralphlaude Sep 16, 2020
11135d7
adapt the init case for the entity
ralphlaude Sep 17, 2020
cb282ad
deal with empty schema in the config
ralphlaude Sep 17, 2020
863dfe3
add comment for already initialized entity
ralphlaude Sep 18, 2020
e511b4b
integrate native crud support in postgres module
ralphlaude Sep 18, 2020
3bc45a0
save CRUD state as byte array
ralphlaude Sep 18, 2020
93a5962
fixed map on slick dbioaction
ralphlaude Sep 18, 2020
dd19ed1
change actor name
ralphlaude Sep 20, 2020
e84d4e6
add infra for CRUD tests in testkit. add exception handling test for …
ralphlaude Sep 22, 2020
6243e4d
Merge branch 'master' into wip-crud-on-top-of-event-sourcing
ralphlaude Sep 22, 2020
624afbf
fixed conflicts and compile errors when merging master
ralphlaude Sep 22, 2020
968c332
fixed format error
ralphlaude Sep 22, 2020
29cdd47
add test for the crud java support
ralphlaude Sep 23, 2020
5cf66b7
remove comments and logs
ralphlaude Sep 23, 2020
bb98d71
changed java 11 for crud sample and fixed conflicting package name
ralphlaude Sep 23, 2020
6a2cd86
Merge branch 'master' into wip-crud-on-top-of-event-sourcing
ralphlaude Sep 25, 2020
8acd3c9
remove concurrency enforcer
ralphlaude Sep 26, 2020
5a97b74
disabled CRUD native support for now
ralphlaude Sep 26, 2020
1b163b3
Add CRUD to expected protocols in TCK
pvlugter Sep 29, 2020
821fd4c
Add default value for cloudstate.proxy.postgres.schema setting
pvlugter Sep 29, 2020
5d9a193
enabled CRUD for the proxy and add readiness-checks
ralphlaude Sep 29, 2020
0248e53
add hikari connection pool properties
ralphlaude Sep 30, 2020
d8f2e9f
fixed protobuf any deserialization
ralphlaude Sep 30, 2020
4c90c02
Merge branch 'master' into wip-crud-on-top-of-event-sourcing
ralphlaude Oct 3, 2020
353b41c
add TCK test for CRUD initial version
ralphlaude Oct 3, 2020
47f7cd3
add TCK test for CRUD and refactoring jdbc store factory
ralphlaude Oct 3, 2020
735257c
Merge remote-tracking branch 'origin/wip-crud-on-top-of-event-sourcin…
ralphlaude Oct 16, 2020
e7ae59c
removed class
ralphlaude Oct 16, 2020
41f189a
Merge branch 'master' into wip-crud-on-top-of-event-sourcing
ralphlaude Oct 16, 2020
3f9789e
add metadata
ralphlaude Oct 16, 2020
eac2e7f
add table creation readiness in native image
ralphlaude Oct 17, 2020
35e0005
rename CRUD to Value Entity
ralphlaude Oct 20, 2020
f820f7f
rename CRUD to Value Entity
ralphlaude Oct 20, 2020
f21b7d0
rename CRUD to Value Entity follow up (crud jdbc configuration to val…
ralphlaude Oct 21, 2020
f65553c
add entity exceptions factory class. extract grpc entity message crea…
ralphlaude Oct 23, 2020
dd30efb
Merge branch 'master' into wip-crud-on-top-of-event-sourcing
ralphlaude Oct 29, 2020
517ee37
integrate tests for entity in circleci
ralphlaude Oct 29, 2020
d4b2493
integrate tests for entity in circleci by building the entity image
ralphlaude Oct 29, 2020
a6bc7d9
integrate tests for entity in circleci by saving the entity image in …
ralphlaude Oct 29, 2020
375f9f9
add jdbc config tests
ralphlaude Oct 29, 2020
a578d6b
Merge branch 'master' into pr/220
pvlugter Nov 1, 2020
87dbd80
Update entity smoke test script
pvlugter Nov 2, 2020
65e5fc8
Fix entity delete in smoke test script
pvlugter Nov 2, 2020
2f6ba27
Add native-image configuration for value entity table
pvlugter Nov 2, 2020
8f1835a
Reduce value entity connection pool size
pvlugter Nov 2, 2020
62f0500
exclude slick dependency from other core persistence module.
ralphlaude Nov 2, 2020
f7e27aa
renaming value entity to entity in the java support, the proxy, the t…
ralphlaude Nov 6, 2020
a2bf57c
fixed native image configuration for value entity
ralphlaude Nov 7, 2020
469edab
write test for properly accessing the state after passivation
ralphlaude Nov 9, 2020
403aed0
fixed grammar
ralphlaude Nov 9, 2020
10c931e
Merge branch 'master' into wip-crud-on-top-of-event-sourcing
ralphlaude Nov 9, 2020
c915048
merge master and refactoring
ralphlaude Nov 9, 2020
5bf6a12
combined readiness checks for eventsourced and value entity
ralphlaude Nov 9, 2020
937084e
fixed readiness check
ralphlaude Nov 9, 2020
5545e6d
removed dedicated readiness check for value entity
ralphlaude Nov 9, 2020
5856394
fixed grammar, remove left crud names and fixed code
ralphlaude Nov 10, 2020
427b538
Merge branch 'master' into pr/220
pvlugter Nov 11, 2020
18cde26
Dynamically create value entity stores
pvlugter Nov 11, 2020
dc786ca
adapt the store-api to able to persist the tpye url of the entity
ralphlaude Nov 11, 2020
340325d
add comment for explaining duplicate shoppingcart.proto
ralphlaude Nov 11, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 31 additions & 4 deletions build.sbt
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,8 @@ val Slf4jSimpleVersion = "1.7.30"
val GraalVersion = "20.1.0"
val DockerBaseImageVersion = "adoptopenjdk/openjdk11:debianslim-jre"
val DockerBaseImageJavaLibraryPath = "${JAVA_HOME}/lib"
val SlickVersion = "3.3.2"
val SlickHikariVersion = "3.3.2"

val excludeTheseDependencies: Seq[ExclusionRule] = Seq(
ExclusionRule("io.netty", "netty"), // grpc-java is using grpc-netty-shaded
Expand Down Expand Up @@ -107,15 +109,16 @@ headerSources in Compile ++= {

lazy val root = (project in file("."))
.enablePlugins(NoPublish)
// Don't forget to add your sbt module here!
// A missing module here can lead to failing Travis test results
// Don't forget to add your sbt module here!
// A missing module here can lead to failing Travis test results
.aggregate(
`protocols`,
`proxy`,
`java-support`,
`java-support-docs`,
`java-support-tck`,
`java-shopping-cart`,
`java-valueentity-shopping-cart`,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Given that we'll seeing the value entities as the default, this implementation of the shopping cart could just be java-shopping-cart, with the event sourced version updated to java-eventsourced-shopping-cart.

We can make the switch to value entities as the default later though too.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I will suggest to switch the value entity as default later. I will keep it mind and write an issue for it. the metrics is an open issue here and should be also done. I will also write a issue for that.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 sounds good. Issues for switching default entity and adding metrics would be useful.

`java-pingpong`,
`akka-client`,
operator,
Expand Down Expand Up @@ -396,8 +399,10 @@ lazy val `proxy-core` = (project in file("proxy/core"))
"com.thesamet.scalapb" %% "scalapb-runtime" % scalapb.compiler.Version.scalapbVersion % "protobuf",
"io.prometheus" % "simpleclient" % PrometheusClientVersion,
"io.prometheus" % "simpleclient_common" % PrometheusClientVersion,
"org.slf4j" % "slf4j-simple" % Slf4jSimpleVersion
"org.slf4j" % "slf4j-simple" % Slf4jSimpleVersion,
//"ch.qos.logback" % "logback-classic" % "1.2.3", // Doesn't work well with SubstrateVM: https://github.com/vmencik/akka-graal-native/blob/master/README.md#logging
"com.typesafe.slick" %% "slick" % SlickVersion,
"com.typesafe.slick" %% "slick-hikaricp" % SlickHikariVersion
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are slick dependencies being added to proxy-core? Seems strange to add here and then exclude in other proxies, rather than have all the slick-based backends together.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with the slick-dependencies only in proxy-jdbc. I am looking for the best option to have it separated.
The in-memory and the jdbc should be somehow pluggable and the in-memory should live in the core. @pvlugter perhaps you have some options here.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The common approach for Lightbend projects is to have a setting in config, that includes a fully qualified class name that can be created dynamically. So that there's something like:

cloudstate.proxy.entity {
  store = in-memory

  in-memory {
    store-class = "fully.qualified.class.name.for.InMemoryStore"
    another-setting-for-in-memory = something
  }
}
# in proxy-jdbc, override setting

cloudstate.proxy.entity {
  store = jdbc

  jdbc {
    store-class = "fully.qualified.class.name.for.JdbcStore"
  }
}

I can take a look at adding this.

),
PB.protoSources in Compile ++= {
val baseDir = (baseDirectory in ThisBuild).value / "protocols"
Expand Down Expand Up @@ -468,6 +473,8 @@ lazy val `proxy-jdbc` = (project in file("proxy/jdbc"))
name := "cloudstate-proxy-jdbc",
dependencyOverrides += "io.grpc" % "grpc-netty-shaded" % GrpcNettyShadedVersion,
libraryDependencies ++= Seq(
//"com.typesafe.slick" %% "slick" % SlickVersion, // should be here for CRUD native support!!
//"com.typesafe.slick" %% "slick-hikaricp" % SlickHikariVersion, // should be here for CRUD native support!!
"com.github.dnvriend" %% "akka-persistence-jdbc" % "3.5.2"
),
fork in run := true,
Expand Down Expand Up @@ -631,7 +638,7 @@ lazy val `java-support-docs` = (project in file("java-support/docs"))
)

lazy val `java-support-tck` = (project in file("java-support/tck"))
.dependsOn(`java-support`, `java-shopping-cart`)
.dependsOn(`java-support`, `java-shopping-cart`, `java-valueentity-shopping-cart`)
.enablePlugins(AkkaGrpcPlugin, AssemblyPlugin, JavaAppPackaging, DockerPlugin, AutomateHeaderPlugin, NoPublish)
.settings(
name := "cloudstate-java-tck",
Expand Down Expand Up @@ -665,6 +672,26 @@ lazy val `java-shopping-cart` = (project in file("samples/java-shopping-cart"))
assemblySettings("java-shopping-cart.jar")
)

lazy val `java-valueentity-shopping-cart` = (project in file("samples/java-valueentity-shopping-cart"))
.dependsOn(`java-support`)
.enablePlugins(AkkaGrpcPlugin, AssemblyPlugin, JavaAppPackaging, DockerPlugin, AutomateHeaderPlugin, NoPublish)
.settings(
name := "java-valueentity-shopping-cart",
dockerSettings,
mainClass in Compile := Some("io.cloudstate.samples.valueentity.shoppingcart.Main"),
PB.generate in Compile := (PB.generate in Compile).dependsOn(PB.generate in (`java-support`, Compile)).value,
akkaGrpcGeneratedLanguages := Seq(AkkaGrpc.Java),
PB.protoSources in Compile ++= {
val baseDir = (baseDirectory in ThisBuild).value / "protocols"
Seq(baseDir / "frontend", baseDir / "example")
},
PB.targets in Compile := Seq(
PB.gens.java -> (sourceManaged in Compile).value
),
javacOptions in Compile ++= Seq("-encoding", "UTF-8", "-source", "11", "-target", "11"),
assemblySettings("java-valueentity-shopping-cart.jar")
)

lazy val `java-pingpong` = (project in file("samples/java-pingpong"))
.dependsOn(`java-support`)
.enablePlugins(AkkaGrpcPlugin, AssemblyPlugin, JavaAppPackaging, DockerPlugin, AutomateHeaderPlugin, NoPublish)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,21 @@
import akka.stream.Materializer;
import com.typesafe.config.Config;
import com.google.protobuf.Descriptors;
import io.cloudstate.javasupport.valueentity.ValueEntity;
import io.cloudstate.javasupport.action.Action;
import io.cloudstate.javasupport.action.ActionHandler;
import io.cloudstate.javasupport.crdt.CrdtEntity;
import io.cloudstate.javasupport.crdt.CrdtEntityFactory;
import io.cloudstate.javasupport.valueentity.ValueEntityFactory;
import io.cloudstate.javasupport.eventsourced.EventSourcedEntity;
import io.cloudstate.javasupport.eventsourced.EventSourcedEntityFactory;
import io.cloudstate.javasupport.impl.AnySupport;
import io.cloudstate.javasupport.impl.action.AnnotationBasedActionSupport;
import io.cloudstate.javasupport.impl.action.ActionService;
import io.cloudstate.javasupport.impl.crdt.AnnotationBasedCrdtSupport;
import io.cloudstate.javasupport.impl.crdt.CrdtStatefulService;
import io.cloudstate.javasupport.impl.valueentity.AnnotationBasedValueEntitySupport;
import io.cloudstate.javasupport.impl.valueentity.ValueEntityStatefulService;
import io.cloudstate.javasupport.impl.eventsourced.AnnotationBasedEventSourcedSupport;
import io.cloudstate.javasupport.impl.eventsourced.EventSourcedStatefulService;

Expand Down Expand Up @@ -145,7 +149,7 @@ public CloudState registerEventSourcedEntity(
}

/**
* Register an event sourced entity factor.
* Register an event sourced entity factory.
*
* <p>This is a low level API intended for custom (eg, non reflection based) mechanisms for
* implementing the entity.
Expand Down Expand Up @@ -300,6 +304,75 @@ public CloudState registerAction(
return this;
}

/**
* Register a annotated value entity.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Register a annotated value entity.
* Register an annotated value entity.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pvlugter if we want to use Entity in the language support and in the proxy. I think, the doc should be Register an annotated entity.. If I understand correctly it is just about renaming ValueEntity to Entity everywhre. I just want to be sure.

Copy link
Contributor

@marcellanz marcellanz Oct 26, 2020

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ralphlaude @pvlugter I'm curious if ValueEntity (previous CRUD) is a ValueEntity or now an Entity, then how does this entity discriminate itself from an "eventsourced" entity, a "crdt" entity and an "action"(?) entity by its naming?

I'm writing this as I found having packages for each state model in Go, where those entities are categorized into being: eventsourced, crdt and action. Similar as we have valueentity/ValueEntity.java I would have to have an entity.Entity or valueentity.Entity as a type, which seems to be a generalized categorization by its name alone. How does that fit into the different state models we have? How is an "entity Entity" a state model?

wdyt?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if we made a good choice of names. Initially this was supposed to be a CrudEntity that would be an Entity capable of doing simple CRUD operations that would be implemented on top of EventSourced support (which seems to me to be an EventSourced specialization), however it became a generic and default entity called Entity or ValueEntity which seemed very confusing. I think we should be explicit about the names of the entity and not support a generic or default entity because the user should want to know what he is doing and nothing better than a name that clearly indicates this.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am inclined to agree with @sleipnir and @marcellanz here. ValueEntity is ambiguous for several reasons (because the word Value is) and because it doesn't really say anything about the state model.

Alternatives:

  • ReadWriteEntity
  • SnapshotEntity
  • MutableEntity
  • FriendlyNeighbourhoodEntity
  • and full-circle: CRUDEntity

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

DurableEntity is another option together with DurableEventSourcedEntity, and eventually DurableReplicatedEntity?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Clearly, a user should not have to think or read more about this (simple?) state model type than she has to for replicated or eventsourced entities. As an example, I'd have not to explain anyone what a KV entity is.

ManagedEntity, all my JPA friends will be happy :)
DataEntity, everything is data, right?
PeristedEntity, we never forget
DurableEntity, we never forget (2)
StateEntity, whatever you think it is.

Guidance:
1: I think it should describe what the proxy does in term of its "inversion of state" duties.
2: Don't know but I found it kind of interesting how little the proxy knows about an entities state structure being just proto.Any blobs (except for certain CRDTs for merging).
3: Yes. One example of this is 'ctx.Fail' is missing in the (new) Go API.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pvlugter @viktorklang you really didn't came to the durable and persisted entity while I wrote that comment at the same time (into my little iPhone Github App), no? 😅

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@marcellanz Great minds think alike. Cloudstate community ftw!

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@marcellanz

Guidance:
1: I think it should describe what the proxy does in term of its "inversion of state" duties.

This is my inclination as well.

2: Don't know but I found it kind of interesting how little the proxy knows about an entities state structure being just proto.Any blobs (except for certain CRDTs for merging).

I find it rather amazing really—how much value it can provide without having to know about the content

3: Yes. One example of this is 'ctx.Fail' is missing in the (new) Go API.

Good point

*
* <p>The entity class must be annotated with {@link ValueEntity}.
*
* @param entityClass The entity class.
* @param descriptor The descriptor for the service that this entity implements.
* @param additionalDescriptors Any additional descriptors that should be used to look up protobuf
* types when needed.
* @return This stateful service builder.
*/
public CloudState registerValueEntity(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the user side, in the language supports, I think we can just use entity for these. So refer to them as Entity and use registerEntity and so on, while event sourced or replicated are specialisations.

Class<?> entityClass,
Descriptors.ServiceDescriptor descriptor,
Descriptors.FileDescriptor... additionalDescriptors) {

ValueEntity entity = entityClass.getAnnotation(ValueEntity.class);
if (entity == null) {
throw new IllegalArgumentException(
entityClass + " does not declare an " + ValueEntity.class + " annotation!");
}

final String persistenceId;
if (entity.persistenceId().isEmpty()) {
persistenceId = entityClass.getSimpleName();
} else {
persistenceId = entity.persistenceId();
}

final AnySupport anySupport = newAnySupport(additionalDescriptors);
ValueEntityStatefulService service =
new ValueEntityStatefulService(
new AnnotationBasedValueEntitySupport(entityClass, anySupport, descriptor),
descriptor,
anySupport,
persistenceId);

services.put(descriptor.getFullName(), system -> service);

return this;
}

/**
* Register a value entity factory.
*
* <p>This is a low level API intended for custom (eg, non reflection based) mechanisms for
* implementing the entity.
*
* @param factory The value entity factory.
* @param descriptor The descriptor for the service that this entity implements.
* @param persistenceId The persistence id for this entity.
* @param additionalDescriptors Any additional descriptors that should be used to look up protobuf
* types when needed.
* @return This stateful service builder.
*/
public CloudState registerValueEntity(
ValueEntityFactory factory,
Descriptors.ServiceDescriptor descriptor,
String persistenceId,
Descriptors.FileDescriptor... additionalDescriptors) {
services.put(
descriptor.getFullName(),
system ->
new ValueEntityStatefulService(
factory, descriptor, newAnySupport(additionalDescriptors), persistenceId));

return this;
}

/**
* Starts a server with the configured entities.
*
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright 2019 Lightbend Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.cloudstate.javasupport.valueentity;

import io.cloudstate.javasupport.ClientActionContext;
import io.cloudstate.javasupport.EffectContext;
import io.cloudstate.javasupport.MetadataContext;

import java.util.Optional;

/**
* A value entity command context.
*
* <p>Methods annotated with {@link CommandHandler} may take this is a parameter. It allows updating
* or deleting the entity state in response to a command, along with forwarding the result to other
* entities, and performing side effects on other entities.
*/
public interface CommandContext<T>
extends ValueEntityContext, ClientActionContext, EffectContext, MetadataContext {

/**
* The name of the command being executed.
*
* @return The name of the command.
*/
String commandName();

/**
* The id of the command being executed.
*
* @return The id of the command.
*/
long commandId();

/**
* Retrieve the state.
*
* @return the current state or empty if none have been created.
* @throws IllegalStateException If the current entity state have been deleted in the command
* invocation.
*/
Optional<T> getState();

/**
* Update the entity with the new state. The state will be persisted.
*
* @param state The state to persist.
*/
void updateState(T state);

/** Delete the entity state. */
void deleteState();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
/*
* Copyright 2019 Lightbend Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.cloudstate.javasupport.valueentity;

import io.cloudstate.javasupport.impl.CloudStateAnnotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* Marks a method on a value entity as a command handler.
*
* <p>This method will be invoked whenever the service call with name that matches this command
* handlers name is invoked.
*
* <p>The method may take the command object as a parameter, its type must match the gRPC service
* input type.
*
* <p>The return type of the method must match the gRPC services output type.
*
* <p>The method may also take a {@link CommandContext}, and/or a {@link
* io.cloudstate.javasupport.EntityId} annotated {@link String} parameter.
*/
@CloudStateAnnotation
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CommandHandler {

/**
* The name of the command to handle.
*
* <p>If not specified, the name of the method will be used as the command name, with the first
* letter capitalized to match the gRPC convention of capitalizing rpc method names.
*
* @return The command name.
*/
String name() default "";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright 2019 Lightbend Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.cloudstate.javasupport.valueentity;

import io.cloudstate.javasupport.impl.CloudStateAnnotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/** A value entity. */
@CloudStateAnnotation
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface ValueEntity {
/**
* The name of the persistence id.
*
* <p>If not specified, defaults to the entities unqualified classname. It's strongly recommended
* that you specify it explicitly.
*/
String persistenceId() default "";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
/*
* Copyright 2019 Lightbend Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package io.cloudstate.javasupport.valueentity;

import io.cloudstate.javasupport.EntityContext;

/** Root context for all value entity contexts. */
public interface ValueEntityContext extends EntityContext {}
Loading