5
5
package akka .persistence .dynamodb .journal
6
6
7
7
import java .time .Instant
8
+ import java .util .concurrent .CompletionException
8
9
9
- import scala .collection .immutable
10
10
import scala .concurrent .ExecutionContext
11
11
import scala .concurrent .Future
12
12
import scala .util .Failure
@@ -41,6 +41,7 @@ import akka.serialization.SerializationExtension
41
41
import akka .serialization .Serializers
42
42
import akka .stream .scaladsl .Sink
43
43
import com .typesafe .config .Config
44
+ import software .amazon .awssdk .services .dynamodb .model .ProvisionedThroughputExceededException
44
45
45
46
/**
46
47
* INTERNAL API
@@ -104,14 +105,14 @@ private[dynamodb] final class DynamoDBJournal(config: Config, cfgPath: String)
104
105
105
106
// if there are pending writes when an actor restarts we must wait for
106
107
// them to complete before we can read the highest sequence number or we will miss it
107
- private val writesInProgress = new java.util.HashMap [String , Future [Done ]]()
108
+ private val writesInProgress = new java.util.HashMap [String , Future [Seq [ Try [ Unit ]] ]]()
108
109
109
110
override def receivePluginInternal : Receive = { case WriteFinished (pid, f) =>
110
111
writesInProgress.remove(pid, f)
111
112
}
112
113
113
- override def asyncWriteMessages (messages : immutable. Seq [AtomicWrite ]): Future [immutable. Seq [Try [Unit ]]] = {
114
- def atomicWrite (atomicWrite : AtomicWrite ): Future [Done ] = {
114
+ override def asyncWriteMessages (messages : Seq [AtomicWrite ]): Future [Seq [Try [Unit ]]] = {
115
+ def atomicWrite (atomicWrite : AtomicWrite ): Future [Seq [ Try [ Unit ]] ] = {
115
116
val serialized : Try [Seq [SerializedJournalItem ]] = Try {
116
117
atomicWrite.payload.map { pr =>
117
118
val (event, tags) = pr.payload match {
@@ -166,7 +167,15 @@ private[dynamodb] final class DynamoDBJournal(config: Config, cfgPath: String)
166
167
ps.publish(pr, serialized.writeTimestamp)
167
168
}
168
169
}
169
- Done
170
+ Nil // successful writes
171
+ }
172
+ .recoverWith { case e : CompletionException =>
173
+ e.getCause match {
174
+ case error : ProvisionedThroughputExceededException => // reject retryable errors
175
+ Future .successful(atomicWrite.payload.map(_ => Failure (error)))
176
+ case error => // otherwise journal failure
177
+ Future .failed(error)
178
+ }
170
179
}
171
180
172
181
case Failure (exc) =>
@@ -175,7 +184,7 @@ private[dynamodb] final class DynamoDBJournal(config: Config, cfgPath: String)
175
184
}
176
185
177
186
val persistenceId = messages.head.persistenceId
178
- val writeResult : Future [Done ] =
187
+ val writeResult : Future [Seq [ Try [ Unit ]] ] =
179
188
if (messages.size == 1 )
180
189
atomicWrite(messages.head)
181
190
else {
@@ -189,7 +198,7 @@ private[dynamodb] final class DynamoDBJournal(config: Config, cfgPath: String)
189
198
writeResult.onComplete { _ =>
190
199
self ! WriteFinished (persistenceId, writeResult)
191
200
}
192
- writeResult.map(_ => Nil )( ExecutionContexts .parasitic)
201
+ writeResult
193
202
}
194
203
195
204
override def asyncDeleteMessagesTo (persistenceId : String , toSequenceNr : Long ): Future [Unit ] = {
0 commit comments