Skip to content

Commit c18e940

Browse files
authored
Merge pull request #180 from lerna-stack/docs-detecting-data-inconsistencies-by-entity-impl
Add documents about entity implementation techniques for detecting data inconsistency issues
2 parents 361b0ca + 1bda681 commit c18e940

File tree

1 file changed

+51
-0
lines changed

1 file changed

+51
-0
lines changed

docs/typed/implementation_guide.md

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,57 @@ Consistency is ensured when it processes operations that can effect outside the
258258
The entity will output results base on the consistent up-to-date state even if under the network partitioning.
259259
The commands will be fail on one side of the partitioned network to keep consistency.
260260

261+
### Detecting data inconsistencies by Entity Implementation
262+
263+
While akka-entity-replication 2.2.0 or above closes some data inconsistency issues,
264+
detecting such inconsistency issues by entity implementation is preferred.
265+
An entity can use the following techniques to detect data inconsistencies:
266+
267+
* To detect an event duplication and miss, use an event number. As the state of the entity, the entity holds the event
268+
number (called LastAppliedEventNumber) of the last event the entity applied itself. Furthermore, the entity puts the
269+
event number (specifically, LastAppliedEventNumber plus one) to an event. The event handler of the entity verifies
270+
that the event has the expected event number (specifically, the event number must be equal to LastAppliedEventNumber
271+
plus one). If this verification fails, either an event duplication or miss has happened.
272+
* To detect an event misdelivery, put the entity ID to an event. The event handler of the entity verifies that the event
273+
has the same entity ID as its own. If this verification fails, an event misdelivery has happened.
274+
275+
The following example illustrates how an entity detects data inconsistencies:
276+
277+
```scala
278+
import lerna.akka.entityreplication.typed._
279+
280+
object MyReplicatedEntity {
281+
final case class Command()
282+
final case class Event(entityId: String, eventNo: Long)
283+
final case class State(lastAppliedEventNo: Long)
284+
285+
def apply(entityContext: ReplicatedEntityContext[Command]): Behavior[Command] =
286+
ReplicatedEntityBehavior[Command, Event, State](
287+
entityContext,
288+
emptyState = State(lastAppliedEventNo = 0),
289+
commandHandler = (state, command) => {
290+
if (??? /* the command is not processed yet */) {
291+
// Replicate an event as below:
292+
// - To detect an event duplication and miss, put the event number (`state.lastAppliedEventNo + 1`) to the event.
293+
// - To detect an event misdelivery, put the entity ID (`entityContext.entityId`) to the event.
294+
Effect.replicate(Event(entityContext.entityId, state.lastAppliedEventNo + 1))
295+
} else {
296+
// Replicate nothing
297+
???
298+
}
299+
},
300+
eventHandler = (state, event) => {
301+
// To detect an event duplication and miss, verifies the event has the expected event number:
302+
require(event.eventNo == state.lastAppliedEventNo + 1)
303+
// To detect an event misdelivery, verifies the event has the expected entity ID:
304+
require(event.entityId == entityContext.entityId)
305+
// The next state must set the event number of the event to LastAppliedEventNo:
306+
State(event.eventNo)
307+
}
308+
)
309+
}
310+
```
311+
261312
### Passivation
262313

263314
You can stop entities that are not used to reduce memory consumption.

0 commit comments

Comments
 (0)