Skip to content

Commit e7e0585

Browse files
authored
Merge pull request #183 from lerna-stack/snapshot-store-reply-with-snapshot-not-found
SnapshotStore can reply with SnapshotNotFound if it is saving an EntitySnapshot
2 parents da0458a + 5660bfc commit e7e0585

File tree

3 files changed

+33
-11
lines changed

3 files changed

+33
-11
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
4141
- Snapshot synchronization could remove committed log entries that not be included in snapshots
4242
[#167](https://github.com/lerna-stack/akka-entity-replication/issues/167)
4343
[#PR168](https://github.com/lerna-stack/akka-entity-replication/pull/168)
44+
- SnapshotStore doesn't reply with SnapshotNotFound sometimes
45+
[#182](https://github.com/lerna-stack/akka-entity-replication/issues/182),
46+
[#PR183](https://github.com/lerna-stack/akka-entity-replication/pull/183)
4447

4548
## [v2.1.0] - 2022-03-24
4649
[v2.1.0]: https://github.com/lerna-stack/akka-entity-replication/compare/v2.0.0...v2.1.0

src/main/scala/lerna/akka/entityreplication/raft/snapshot/SnapshotStore.scala

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,8 +96,11 @@ private[entityreplication] class SnapshotStore(
9696
cmd.entityId,
9797
)
9898
case FetchSnapshot(_, replyTo) =>
99-
prevSnapshot.foreach { s =>
100-
replyTo ! SnapshotProtocol.SnapshotFound(s)
99+
prevSnapshot match {
100+
case Some(prevSnapshot) =>
101+
replyTo ! SnapshotProtocol.SnapshotFound(prevSnapshot)
102+
case None =>
103+
replyTo ! SnapshotProtocol.SnapshotNotFound(entityId)
101104
}
102105
}
103106
case _: persistence.SaveSnapshotSuccess =>

src/test/scala/lerna/akka/entityreplication/raft/snapshot/ShardSnapshotStoreFailureSpec.scala

Lines changed: 25 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,6 @@ import lerna.akka.entityreplication.raft.{ ActorSpec, RaftSettings }
2222
import lerna.akka.entityreplication.testkit.KryoSerializable
2323

2424
import scala.concurrent.Promise
25-
import scala.util.Using
2625

2726
object ShardSnapshotStoreFailureSpec {
2827
final case object DummyState extends KryoSerializable
@@ -93,34 +92,41 @@ class ShardSnapshotStoreFailureSpec
9392
"ShardSnapshotStore (with time-consuming writes)" should {
9493

9594
// Emulates a time-consuming write
96-
class TimeConsumingWriteSnapshotPolicy extends SnapshotStorage.SnapshotPolicies.PolicyType with AutoCloseable {
95+
// Note:
96+
// The promise (`processingResultPromise`) must be fulfilled.
97+
// The succeeding tests will fail unless the promise is fulfilled.
98+
class TimeConsumingWriteSnapshotPolicy extends SnapshotStorage.SnapshotPolicies.PolicyType {
9799
val processingResultPromise = Promise[ProcessingResult]()
98100
override def tryProcess(persistenceId: String, processingUnit: SnapshotOperation): ProcessingResult = {
99101
processingUnit match {
100102
case _: WriteSnapshot => processingResultPromise.future.await
101103
case _ => ProcessingSuccess
102104
}
103105
}
104-
override def close(): Unit = {
106+
def trySuccess(): Unit = {
105107
processingResultPromise.trySuccess(ProcessingSuccess)
106108
}
107109
}
108110

109-
"reply with `SnapshotNotFound` to `FetchSnapshot` if it has no EntitySnapshot and is saving an EntitySnapshot" ignore {
110-
// TODO Change SnapshotStore.savingSnapshot such that this test passes.
111+
"reply with `SnapshotNotFound` to `FetchSnapshot` if it has no EntitySnapshot and is saving an EntitySnapshot" in {
111112
val entityId = generateUniqueEntityId()
112113
val shardSnapshotStore = createShardSnapshotStore()
113114
val metadata = EntitySnapshotMetadata(entityId, LogEntryIndex(1))
114115
val snapshot = EntitySnapshot(metadata, EntityState(DummyState))
115116

116-
Using(new TimeConsumingWriteSnapshotPolicy()) { timeConsumingWriteSnapshotPolicy =>
117+
val timeConsumingWriteSnapshotPolicy = new TimeConsumingWriteSnapshotPolicy()
118+
try {
117119
// Prepare: SnapshotStore is saving the snapshot
118120
snapshotTestKit.withPolicy(timeConsumingWriteSnapshotPolicy)
119121
shardSnapshotStore ! SaveSnapshot(snapshot, replyTo = testActor)
120122

121123
// Test:
122124
shardSnapshotStore ! FetchSnapshot(entityId, replyTo = testActor)
123-
expectMsg(SnapshotNotFound)
125+
expectMsg(SnapshotNotFound(entityId))
126+
} finally {
127+
// Cleanup:
128+
// The succeeding tests will fail unless the promise is fulfilled.
129+
timeConsumingWriteSnapshotPolicy.trySuccess()
124130
}
125131
}
126132

@@ -134,7 +140,8 @@ class ShardSnapshotStoreFailureSpec
134140
shardSnapshotStore ! SaveSnapshot(firstSnapshot, replyTo = testActor)
135141
expectMsg(SaveSnapshotSuccess(firstSnapshotMetadata))
136142

137-
Using(new TimeConsumingWriteSnapshotPolicy()) { timeConsumingWriteSnapshotPolicy =>
143+
val timeConsumingWriteSnapshotPolicy = new TimeConsumingWriteSnapshotPolicy()
144+
try {
138145
// Prepare: SnapshotStore is saving the second snapshot
139146
snapshotTestKit.withPolicy(timeConsumingWriteSnapshotPolicy)
140147
val secondSnapshot =
@@ -144,6 +151,10 @@ class ShardSnapshotStoreFailureSpec
144151
// Test:
145152
shardSnapshotStore ! FetchSnapshot(entityId, replyTo = testActor)
146153
expectMsg(SnapshotFound(firstSnapshot))
154+
} finally {
155+
// Cleanup:
156+
// The succeeding tests will fail unless the promise is fulfilled.
157+
timeConsumingWriteSnapshotPolicy.trySuccess()
147158
}
148159
}
149160

@@ -155,7 +166,8 @@ class ShardSnapshotStoreFailureSpec
155166
val metadata = EntitySnapshotMetadata(entityId, LogEntryIndex(1))
156167
val snapshot = EntitySnapshot(metadata, EntityState(DummyState))
157168

158-
Using(new TimeConsumingWriteSnapshotPolicy()) { timeConsumingWriteSnapshotPolicy =>
169+
val timeConsumingWriteSnapshotPolicy = new TimeConsumingWriteSnapshotPolicy()
170+
try {
159171
// Prepare: SnapshotStore is saving the snapshot
160172
snapshotTestKit.withPolicy(timeConsumingWriteSnapshotPolicy)
161173
shardSnapshotStore ! SaveSnapshot(snapshot, replyTo = testActor)
@@ -168,6 +180,10 @@ class ShardSnapshotStoreFailureSpec
168180
shardSnapshotStore ! SaveSnapshot(snapshot, replyTo = testActor)
169181
}
170182
expectNoMessage()
183+
} finally {
184+
// Cleanup:
185+
// The succeeding tests will fail unless the promise is fulfilled.
186+
timeConsumingWriteSnapshotPolicy.trySuccess()
171187
}
172188
}
173189

0 commit comments

Comments
 (0)