This is an automated email from the ASF dual-hosted git repository.
pjfanning pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/pekko-projection.git
The following commit(s) were added to refs/heads/main by this push:
new 47ae3e49 update docs to include changes from akka projections 1.4.1
(#505)
47ae3e49 is described below
commit 47ae3e490e9abe68944bf9fe295cb15ab5946aa4
Author: PJ Fanning <[email protected]>
AuthorDate: Mon Jun 1 18:25:10 2026 +0100
update docs to include changes from akka projections 1.4.1 (#505)
* Sync docs with akka 1.4.x
Co-authored-by: Copilot <[email protected]>
some reverts
Update running.md
Update snapshots.md
revert
Create intro-video.png
reverts
more
more
more
more
more
more
more
more reverts
Update running.md
revert
Update index.md
* more
* more
* merge issues
* Update slick.md
* more
* more
* links
* Update jdbc.md
* Update slick.md
* fix fqcns
* Update setup-your-app.md
* Replace pekko.apache.org/docs/pekko/current/ links with @extref format
* temp enable link validator
* Update link-validator.yml
* more reverts
* more fixes
* Update build.sbt
---------
Co-authored-by: copilot-swe-agent[bot]
<[email protected]>
---
build.sbt | 14 +-
docs/src/main/paradox/actor.md | 8 +-
docs/src/main/paradox/cassandra.md | 18 +-
docs/src/main/paradox/classic.md | 8 +-
docs/src/main/paradox/durable-state.md | 16 +-
docs/src/main/paradox/error.md | 4 +-
docs/src/main/paradox/eventsourced.md | 12 +-
.../paradox/getting-started/event-generator-app.md | 4 +-
docs/src/main/paradox/getting-started/index.md | 4 +-
.../paradox/getting-started/projection-handler.md | 4 +-
.../paradox/getting-started/running-cluster.md | 40 ++---
docs/src/main/paradox/getting-started/running.md | 6 +-
.../main/paradox/getting-started/setup-your-app.md | 10 +-
.../paradox/getting-started/source-provider.md | 4 +-
docs/src/main/paradox/getting-started/testing.md | 6 +-
.../grpc-replicated-event-sourcing-transport.md | 185 +++++++++++++++++++++
docs/src/main/paradox/grpc.md | 172 ++++++++++++++++---
docs/src/main/paradox/index.md | 5 +-
docs/src/main/paradox/jdbc.md | 38 ++---
docs/src/main/paradox/kafka.md | 8 +-
docs/src/main/paradox/management.md | 4 +-
docs/src/main/paradox/overview.md | 25 +--
docs/src/main/paradox/projection-settings.md | 2 +-
docs/src/main/paradox/r2dbc.md | 13 +-
.../src/main/paradox/release-notes/releases-1.0.md | 4 +-
docs/src/main/paradox/running.md | 17 +-
docs/src/main/paradox/slick.md | 20 +--
docs/src/main/paradox/snapshots.md | 2 +-
docs/src/main/paradox/testing.md | 16 +-
docs/src/main/paradox/use-cases.md | 2 +-
project/Dependencies.scala | 4 +-
31 files changed, 491 insertions(+), 184 deletions(-)
diff --git a/build.sbt b/build.sbt
index 9d5e9389..a6b1aea1 100644
--- a/build.sbt
+++ b/build.sbt
@@ -293,19 +293,29 @@ lazy val docs = project
"canonical.base_url" ->
"https://pekko.apache.org/docs/pekko-projection/current",
"github.base_url" -> "https://github.com/apache/pekko-projection",
"pekko.version" -> Dependencies.Versions.pekko,
+ "pekko.r2dbc.version" -> Dependencies.Versions.pekkoPersistenceR2dbc,
// Pekko
"extref.pekko.base_url" ->
s"https://pekko.apache.org/docs/pekko/${Dependencies.PekkoVersionInDocs}/%s",
"scaladoc.pekko.base_url" ->
s"https://pekko.apache.org/api/pekko/${Dependencies.PekkoVersionInDocs}/",
"javadoc.pekko.base_url" ->
s"https://pekko.apache.org/japi/pekko/${Dependencies.PekkoVersionInDocs}/",
"javadoc.pekko.link_style" -> "direct",
+ "extref.pekko-grpc.base_url" ->
+
s"https://pekko.apache.org/docs/pekko-grpc/${Dependencies.PekkoGrpcVersionInDocs}/%s",
+ "scaladoc.org.apache.pekko.grpc.base_url" ->
+
s"https://pekko.apache.org/api/pekko-grpc/${Dependencies.PekkoGrpcVersionInDocs}",
+ "javadoc.org.apache.pekko.grpc.base_url" ->
+
s"https://pekko.apache.org/api/pekko-grpc/${Dependencies.PekkoGrpcVersionInDocs}",
+ "javadoc.org.apache.pekko.grpc.link_style" -> "direct",
"extref.pekko-persistence-r2dbc.base_url" ->
s"https://pekko.apache.org/docs/pekko-persistence-r2dbc/${Dependencies.PekkoPersistenceR2dbcVersionInDocs}/%s",
"scaladoc.org.apache.pekko.persistence.r2dbc.base_url" ->
s"https://pekko.apache.org/api/pekko-persistence-r2dbc/${Dependencies.PekkoPersistenceR2dbcVersionInDocs}",
"javadoc.org.apache.pekko.persistence.r2dbc.base_url" ->
-
s"https://pekko.apache.org/japi/pekko-persistence-r2dbc/${Dependencies.PekkoPersistenceR2dbcVersionInDocs}",
+
s"https://pekko.apache.org/api/pekko-persistence-r2dbc/${Dependencies.PekkoPersistenceR2dbcVersionInDocs}",
+ "javadoc.org.apache.pekko.persistence.r2dbc.link_style" -> "direct",
// Java
- "javadoc.base_url" -> "https://docs.oracle.com/javase/8/docs/api/",
+ "javadoc.base_url" ->
"https://docs.oracle.com/en/java/javase/17/docs/api/java.base/",
+ "javadoc.link_style" -> "direct",
// Scala
"scaladoc.scala.base_url" ->
s"https://www.scala-lang.org/api/${scalaBinaryVersion.value}.x/",
"scaladoc.pekko.projection.base_url" -> s"/${(Preprocess /
siteSubdirName).value}/",
diff --git a/docs/src/main/paradox/actor.md b/docs/src/main/paradox/actor.md
index 902322aa..c28a4cf1 100644
--- a/docs/src/main/paradox/actor.md
+++ b/docs/src/main/paradox/actor.md
@@ -1,9 +1,9 @@
# Processing with Actor
-A good alternative for advanced state management is to implement the handler
as an [actor](https://pekko.apache.org/docs/pekko/current/typed/actors.html).
+A good alternative for advanced state management is to implement the handler
as an @extref:[actor](pekko:typed/actors.html).
The following example is using the `CassandraProjection` but the handler and
actor would be the same if used
-any other @ref:[offset storage](overview.md).
+any other @ref:[offset storage](overview.md).
An actor `Behavior` for the word count example that was introduced in the
section about @ref:[Stateful handler](cassandra.md#stateful-handler):
@@ -37,10 +37,10 @@ successful or failed.
The lifecycle of the actor is managed by the `Projection`. The actor is
automatically stopped when the `Projection` is stopped.
Another implementation that is loading the current count for a word on demand,
and thereafter caches it in the
-in-memory state:
+in-memory state:
Scala
: @@snip
[WordCountDocExample.scala](/integration-examples/src/test/scala/docs/cassandra/WordCountDocExample.scala)
{ #behaviorLoadingOnDemand }
Java
-: @@snip
[WordCountDocExample.java](/integration-examples/src/test/java/jdocs/cassandra/WordCountDocExample.java)
{ #behaviorLoadingOnDemand }
+: @@snip
[WordCountDocExample.java](/integration-examples/src/test/java/jdocs/cassandra/WordCountDocExample.java)
{ #behaviorLoadingOnDemand }
diff --git a/docs/src/main/paradox/cassandra.md
b/docs/src/main/paradox/cassandra.md
index 91bacdea..608c92f3 100644
--- a/docs/src/main/paradox/cassandra.md
+++ b/docs/src/main/paradox/cassandra.md
@@ -1,4 +1,4 @@
-# Offset in Cassandra
+# Offset in Apache Cassandra
The @apidoc[CassandraProjection$] has support for storing the offset in
Cassandra.
@@ -125,7 +125,7 @@ one envelope at a time and visibility guarantees between
the invocations are han
or other concurrency primitives are needed for managing the state.
The returned @scala[`Future[Done]`]@java[`CompletionStage<Done>`] is to be
completed when the processing of the
-`envelope` has finished. The handler will not be invoked with the next
envelope until after the returned
+`envelope` has finished. The handler will not be invoked with the next
envelope until after the returned
@scala[`Future[Done]`]@java[`CompletionStage<Done>`] has been completed.
Scala
@@ -140,7 +140,7 @@ It is important that the `Handler` instance is not shared
between several `Proje
because then it would be invoked concurrently, which is not how it is intended
to be used. Each `Projection`
instance should use a new `Handler` instance. This is the reason why the
handler parameter is a factory
@scala[(`() =>`)]@java[(`Supplier`)] of the handler. A new handler instance is
also created when the projection
-is restarted.
+is restarted.
@@@
@@ -149,7 +149,7 @@ error prone to manage the state in variables of the
`Handler`. For that purpose
is provided.
Let us look at how a `StatefulHandler` can be implemented in the context of a
"word count" domain. The purpose is
-to process a stream of words and for each word keep track of how many times it
has occurred.
+to process a stream of words and for each word keep track of how many times it
has occurred.
Given an envelope and `SourceProvider` for this example:
@@ -177,7 +177,7 @@ Java
The `handler` can be implemented as follows.
-A naive approach would be to have one row per word for storing the current
count in the database.
+A naive approach would be to have one row per word for storing the current
count in the database.
The handler could be implemented as a completely stateless handler that for
each processed envelope loads the current
count from the database, increment the count by 1 and saved it again.
Typically there will be several instances of the
`Projection` with different `ProjectionId.id`. Each `Projection` instance
would be responsible for processing a subset
@@ -196,7 +196,7 @@ Scala
Java
: @@snip
[WordCountDocExample.java](/integration-examples/src/test/java/jdocs/cassandra/WordCountDocExample.java)
{ #StatefulHandler-imports #loadingInitialState }
-The `StatefulHandler` has two methods that needs to be implemented.
+The `StatefulHandler` has two methods that needs to be implemented.
* `initialState` - Invoked to load the initial state when the projection is
started or if previous `process` failed.
* `process(state, envelope)` - Invoked for each `Envelope`, one at a time. The
`state` parameter is the completed
@@ -215,7 +215,7 @@ Java
### Actor handler
-A good alternative for advanced state management is to implement the handler
as an [actor](https://pekko.apache.org/docs/pekko/current/typed/actors.html),
+A good alternative for advanced state management is to implement the handler
as an @extref:[actor](pekko:typed/actors.html),
which is described in @ref:[Processing with Actor](actor.md).
### Flow handler
@@ -308,7 +308,7 @@ pekko.projection.cassandra {
}
```
-or share the same Cassandra session as [Pekko Connectors
Cassandra](https://pekko.apache.org/docs/pekko-connectors/current/cassandra.html):
+or share the same Cassandra session as [Apache Pekko Connectors
Cassandra](https://pekko.apache.org/docs/pekko-connectors/current/cassandra.html):
```
pekko.projection.cassandra {
@@ -332,6 +332,6 @@ datastax-java-driver {
```
Alternatively, Pekko Discovery can be used for finding the Cassandra server
contact points as described
-in the [Pekko Connectors Cassandra
documentation](https://pekko.apache.org/docs/pekko-connectors/current/cassandra.html#using-pekko-discovery).
+in the [Apache Pekko Connectors Cassandra
documentation](https://pekko.apache.org/docs/pekko-connectors/current/cassandra.html#using-pekko-discovery).
Without any configuration it will use `localhost:9042` as default.
diff --git a/docs/src/main/paradox/classic.md b/docs/src/main/paradox/classic.md
index 875839ac..335ebaa2 100644
--- a/docs/src/main/paradox/classic.md
+++ b/docs/src/main/paradox/classic.md
@@ -1,7 +1,7 @@
# Pekko Classic
-Apache Pekko Projections can be used with the [new Actor
API](https://pekko.apache.org/docs/pekko/current/typed/actors.html) or
-the [classic Actor
API](https://pekko.apache.org/docs/pekko/current/index-classic.html). The
documentation samples
+Apache Pekko Projections can be used with the @extref:[new Actor
API](pekko:typed/actors.html) or
+the @extref:[classic Actor API](pekko:index-classic.html). The documentation
samples
show the new Actor API, and this page highlights how to use it with the
classic Actor API.
## Actor System
@@ -17,10 +17,10 @@ Java
## PersistentActor
-@ref:[Events from Pekko Classic Persistence](eventsourced.md) can be emitted
from `PersistentActor` and consumed by a
+@ref:[Events from Apache Pekko Classic Persistence](eventsourced.md) can be
emitted from `PersistentActor` and consumed by a
Projection with the @apidoc[EventSourcedProvider$]. The events from the
`PersistentActor` must be tagged by wrapping
them in `org.apache.pekko.persistence.journal.Tagged`, which can be done in
the `PersistentActor` or by using
-[Event
Adapters](https://pekko.apache.org/docs/pekko/current/persistence.html#event-adapters).
+:[Event Adapters](pekko:persistence.html#event-adapters).
## Running
diff --git a/docs/src/main/paradox/durable-state.md
b/docs/src/main/paradox/durable-state.md
index d604c37d..8c2d1d69 100644
--- a/docs/src/main/paradox/durable-state.md
+++ b/docs/src/main/paradox/durable-state.md
@@ -1,9 +1,13 @@
# Changes from Durable State
-A typical source for Projections is the change stored with
@apidoc[DurableStateBehavior$] in [Apache Pekko
Persistence](https://pekko.apache.org/docs/pekko/current/typed/durable-state/persistence.html).
Durable state changes can be
[tagged](https://pekko.apache.org/docs/pekko/current/typed/durable-state/persistence.html#tagging)
and then
-consumed with the [changes
query](https://pekko.apache.org/docs/pekko/current/durable-state/persistence-query.html#using-query-with-pekko-projections).
+A typical source for Projections is the change stored with
@apidoc[DurableStateBehavior$] in @extref:[Apache Pekko
Persistence](pekko:typed/durable-state/persistence.html). Durable state changes
can be @extref:[tagged](pekko:typed/durable-state/persistence.html#tagging) and
then
+consumed with the @extref:[changes
query](pekko:durable-state/persistence-query.html#using-query-with-pekko-projections).
-Apache Pekko Projections has integration with `changes`, which is described
here.
+Apache Pekko Projections has integration with `changes`, which is described
here.
+
+@@@ note { title=Alternative }
+When using the R2DBC plugin an alternative to using a Projection is to
@extref:[store the query
representation](pekko-persistence-r2dbc:durable-state-store.html#storing-query-representation)
directly from the write side.
+@@@
## Dependencies
@@ -43,7 +47,7 @@ This source is consuming all the changes from the `Account`
`DurableStateBehavio
The
@scala[`DurableStateChange[AccountEntity.Account]`]@java[`DurableStateChange<AccountEntity.Account>`]
is what the `Projection`
handler will process. It contains the `State` and additional meta data, such
as the offset that will be stored
-by the `Projection`. See @apidoc[pekko.persistence.query.DurableStateChange]
for full details of what it contains.
+by the `Projection`. See @apidoc[pekko.persistence.query.DurableStateChange]
for full details of what it contains.
## SourceProvider for changesBySlices
@@ -56,11 +60,11 @@ Scala
Java
: @@snip
[DurableStateStoreDocExample.java](/examples/src/test/java/jdocs/state/DurableStateStoreBySlicesDocExample.java)
{ #changesBySlicesSourceProvider }
-This example is using the [R2DBC plugin for Apache Pekko
Persistence](https://pekko.apache.org/docs/pekko-persistence-r2dbc/current/query.html).
+This example is using the @extref:[R2DBC plugin for Apache Pekko
Persistence](pekko-persistence-r2dbc:query.html).
You will use the same plugin that you configured for the write side. The one
that is used by the `DurableStateBehavior`.
This source is consuming all the changes from the `Account`
`DurableStateBehavior` for the given slice range. In a production application,
you would need to start as many instances as the number of slice ranges. That
way you consume the changes from all entities.
The
@scala[`DurableStateChange[AccountEntity.Account]`]@java[`DurableStateChange<AccountEntity.Account>`]
is what the `Projection`
handler will process. It contains the `State` and additional meta data, such
as the offset that will be stored
-by the `Projection`. See @apidoc[pekko.persistence.query.DurableStateChange]
for full details of what it contains.
+by the `Projection`. See @apidoc[pekko.persistence.query.DurableStateChange]
for full details of what it contains.
diff --git a/docs/src/main/paradox/error.md b/docs/src/main/paradox/error.md
index 8ab3df14..c6b8919b 100644
--- a/docs/src/main/paradox/error.md
+++ b/docs/src/main/paradox/error.md
@@ -33,7 +33,7 @@ If the recovery strategy is not defined on the `Projection`
the default is `fail
in configuration:
@@snip [reference.conf](/core/src/main/resources/reference.conf) {
#recovery-strategy }
-
+
## Projection restart
@@ -52,7 +52,7 @@ Scala
Java
: @@snip
[CassandraProjectionDocExample.java](/integration-examples/src/test/java/jdocs/cassandra/CassandraProjectionDocExample.java)
{ #withRestartBackoff }
-
+
If the recovery strategy is not defined on the `Projection` the default is
defined in configuration:
@@snip [reference.conf](/core/src/main/resources/reference.conf) {
#restart-backoff }
diff --git a/docs/src/main/paradox/eventsourced.md
b/docs/src/main/paradox/eventsourced.md
index 90783255..48279b89 100644
--- a/docs/src/main/paradox/eventsourced.md
+++ b/docs/src/main/paradox/eventsourced.md
@@ -1,9 +1,9 @@
# Events from Apache Pekko Persistence
-A typical source for Projections is events stored with
@apidoc[EventSourcedBehavior$] in [Apache Pekko
Persistence](https://pekko.apache.org/docs/pekko/current/typed/persistence.html).
Events can be
[tagged](https://pekko.apache.org/docs/pekko/current/typed/persistence.html#tagging)
and then
-consumed with the [eventsByTag
query](https://pekko.apache.org/docs/pekko/current/persistence-query.html#eventsbytag-and-currenteventsbytag).
+A typical source for Projections is events stored with
@apidoc[EventSourcedBehavior$] in @extref:[Apache Pekko
Persistence](pekko:typed/persistence.html). Events can be
@extref:[tagged](pekko:typed/persistence.html#tagging) and then
+consumed with the @extref:[eventsByTag
query](pekko:persistence-query.html#eventsbytag-and-currenteventsbytag).
-Apache Pekko Projections has integration with `eventsByTag`, which is
described here.
+Apache Pekko Projections has integration with `eventsByTag`, which is
described here.
## Dependencies
@@ -37,7 +37,7 @@ Java
: @@snip
[EventSourcedDocExample.java](/examples/src/test/java/jdocs/eventsourced/EventSourcedDocExample.java)
{ #eventsByTagSourceProvider }
This example is using the [Cassandra plugin for Apache Pekko
Persistence](https://pekko.apache.org/docs/pekko-persistence-cassandra/current/read-journal.html),
-but same code can be used for other Apache Pekko Persistence plugins by
replacing the `CassandraReadJournal.Identifier`.
+but same code can be used for other Pekko Persistence plugins by replacing the
`CassandraReadJournal.Identifier`.
For example the [JDBC
plugin](https://pekko.apache.org/docs/pekko-persistence-jdbc/current/) can be
used. You will
use the same plugin as you have configured for the write side that is used by
the `EventSourcedBehavior`.
@@ -48,7 +48,7 @@ The tags are assigned as described in @ref:[Tagging Events in
EventSourcedBehavi
The
@scala[`EventEnvelope[ShoppingCart.Event]`]@java[`EventEnvelope<ShoppingCart.Event>`]
is what the `Projection`
handler will process. It contains the `Event` and additional meta data, such
as the offset that will be stored
by the `Projection`. See @apidoc[pekko.projection.eventsourced.EventEnvelope]
for full details of what the
-envelope contains.
+envelope contains.
## SourceProvider for eventsBySlices
@@ -61,7 +61,7 @@ Scala
Java
: @@snip
[EventSourcedDocExample.java](/examples/src/test/java/jdocs/eventsourced/EventSourcedBySlicesDocExample.java)
{ #eventsBySlicesSourceProvider }
-This example is using the [R2DBC plugin for Apache Pekko
Persistence](https://pekko.apache.org/docs/pekko-persistence-r2dbc/current/query.html).
+This example is using the @extref:[R2DBC plugin for Apache Pekko
Persistence](pekko-persistence-r2dbc:query.html).
You will use the same plugin as you have configured for the write side that is
used by the `EventSourcedBehavior`.
This source is consuming all events from the `ShoppingCart`
`EventSourcedBehavior` for the given slice range. In a production application,
you would need to start as many instances as the number of slice ranges. That
way you consume the events from all entities.
diff --git a/docs/src/main/paradox/getting-started/event-generator-app.md
b/docs/src/main/paradox/getting-started/event-generator-app.md
index 308a7ba1..4f2fe41e 100644
--- a/docs/src/main/paradox/getting-started/event-generator-app.md
+++ b/docs/src/main/paradox/getting-started/event-generator-app.md
@@ -3,8 +3,8 @@
This is a simulation of fake Event Sourced shopping carts. The details of this
implementation is not
important for understanding Projections. It's needed for @ref:[running the
example](running.md).
-Please look at the [Apache Pekko reference documentation for Event
Sourcing](https://pekko.apache.org/docs/pekko/current/typed/persistence.html)
-for how to implement real `EventSourcedBehavior`.
+Please look at the @extref:[Apache Pekko reference documentation for Event
Sourcing](pekko:typed/persistence.html)
+for how to implement real `EventSourcedBehavior`.
Add the `EventGeneratorApp` to your project:
diff --git a/docs/src/main/paradox/getting-started/index.md
b/docs/src/main/paradox/getting-started/index.md
index 7e8939eb..68457d67 100644
--- a/docs/src/main/paradox/getting-started/index.md
+++ b/docs/src/main/paradox/getting-started/index.md
@@ -3,6 +3,8 @@
By now you should understand the fundamental concepts of how a Projection
works by reading about its @ref:[use cases](../use-cases.md).
This guide will briefly describe the basic components of a Projection and
instruct you step-by-step on how to build a functioning application.
+The aim is to build a full
@ref:[CQRS](../use-cases.md#command-query-responsibility-segregation-cqrs-)
(Command Query Responsibility Segregation) ES (Event Sourcing) system using a
combination of features from the Apache Pekko toolkit.
+
@@toc { depth=2 }
@@@ index
@@ -12,7 +14,7 @@ This guide will briefly describe the basic components of a
Projection and instru
* [Build a Stateful Projection handler](projection-handler.md)
* [Writing tests for a Projection](testing.md)
* [Running the Projection](running.md)
-* [Running the Projection in Apache Pekko Cluster](running-cluster.md)
+* [Running the Projection in an Apache Pekko Cluster](running-cluster.md)
@@@
diff --git a/docs/src/main/paradox/getting-started/projection-handler.md
b/docs/src/main/paradox/getting-started/projection-handler.md
index 2043153f..ceeb7718 100644
--- a/docs/src/main/paradox/getting-started/projection-handler.md
+++ b/docs/src/main/paradox/getting-started/projection-handler.md
@@ -25,7 +25,7 @@ Each row in `item_popularity` contains a shopping cart item
id and a count that
The example will persist the item popularity count with a [Cassandra
counter](https://docs.datastax.com/en/cql-oss/3.x/cql/cql_reference/counter_type.html)
data type.
It's not possible to guarantee that item count updates occur idempotently
because we are using at-least-once semantics.
-However, since the count is only a rough metric to judge how popular an item
is it's not critical to have a totally accurate figure.
+However, since the count is only a rough metric to judge how popular an item
is it's not critical to have a totally accurate figure.
@@@
@@ -41,7 +41,7 @@ Now it's time to write the Projection handler itself.
This example uses a @apidoc[Handler] that will process
`ShoppingCartEvents.Event` events from the @apidoc[SourceProvider] that we
implemented earlier.
Specifically, it will only process `ItemEvents` that modify the items added or
removed from a shopping cart.
It will ignore all shopping cart `Checkout` events by skipping them.
-The event envelopes are processed in the `process` method.
+The event envelopes are processed in the `process` method.
This example will also log the popularity count of every 10th item event that
is processed.
The logging counter is stored as a mutable variable within the handler.
diff --git a/docs/src/main/paradox/getting-started/running-cluster.md
b/docs/src/main/paradox/getting-started/running-cluster.md
index 33ec8f6d..e2c905bc 100644
--- a/docs/src/main/paradox/getting-started/running-cluster.md
+++ b/docs/src/main/paradox/getting-started/running-cluster.md
@@ -1,9 +1,9 @@
-# Running the Projection in Apache Pekko Cluster
+# Running the Projection in an Apache Pekko Cluster
-Running the Projection with [Apache Pekko
Cluster](https://pekko.apache.org/docs/pekko/current/typed/cluster.html) allows
us to add two important aspects to our system: availability and scalability.
+Running the Projection with @extref:[Apache Pekko
Cluster](pekko:typed/cluster.html) allows us to add two important aspects to
our system: availability and scalability.
A Projection running as a single Actor creates a single point of failure
(availability), when the app shuts down for any reason, the projection is no
longer running until it's started again.
A Projection running as a single Actor creates a processing bottleneck
(scalability), all messages from the @apidoc[SourceProvider] are processed by a
single Actor on a single machine.
-By using a [Sharded Daemon
Process](https://pekko.apache.org/docs/pekko/current/typed/cluster-sharded-daemon-process.html#sharded-daemon-process)
with Apache Pekko Cluster and [Apache Pekko Cluster
Sharding](https://pekko.apache.org/docs/pekko/current/typed/cluster-sharding.html)
we can scale up the Projection and make it more available by running at least
as many instances of the same Projection as we have cluster members.
+By using a @extref:[Sharded Daemon
Process](pekko:typed/cluster-sharded-daemon-process.html#sharded-daemon-process)
with Apache Pekko Cluster and @extref:[Apache Pekko Cluster
Sharding](pekko:typed/cluster-sharding.html) we can scale up the Projection and
make it more available by running at least as many instances of the same
Projection as we have cluster members.
As Pekko cluster members join and leave the cluster the Sharded Daemon Process
will automatically scale and rebalance Sharded Daemon Processes (Projection
instances) accordingly.
Running the Projection as a Sharded Daemon Process requires no changes to our
projection handler and repository, we only need to change the way in which the
actor that runs the Projection is initialized.
@@ -23,7 +23,7 @@ Scala
Java
: @@snip
[ShoppingCartClusterApp.java](/examples/src/test/java/jdocs/guide/ShoppingCartClusterApp.java)
{ #guideClusterSetup }
-
+
Before running the app we must first run the `EventGeneratorApp` in `cluster`
mode in order to generate new shopping cart events for multiple tags, instead
of just one.
Shopping cart events are tagged in a similar way to the sharded entities
themselves.
Given a sequence of tags from `0..n` a hash is generated using the sharding
entity key, the shopping cart id.
@@ -55,7 +55,7 @@ mvn compile exec:java
-Dexec.mainClass="jdocs.guide.EventGeneratorApp" -Dexec.ar
When the app is running you will observe that the logs show events written to
different tags (`carts-0`, `carts-1`, etc.), instead of just one
(`shopping-cart`).
```
-[2020-08-13 15:18:58,383] [INFO] [docs.guide.EventGeneratorApp$] []
[EventGenerator-org.apache.pekko.actor.default-dispatcher-19] - id [6059e] tag
[carts-1] event: ItemQuantityAdjusted(6059e,cat t-shirt,1,2) MDC:
{persistencePhase=persist-evt,
pekkoAddress=pekko://[email protected]:73350,
pekkoSource=pekko://EventGenerator/system/sharding/shopping-cart-event/903/6059e,
sourceActorSystem=EventGenerator, persistenceId=6059e}
+[2020-08-13 15:18:58,383] [INFO] [docs.guide.EventGeneratorApp$] []
[EventGenerator-pekko.actor.default-dispatcher-19] - id [6059e] tag [carts-1]
event: ItemQuantityAdjusted(6059e,cat t-shirt,1,2) MDC:
{persistencePhase=persist-evt,
pekkoAddress=pekko://[email protected]:73350,
pekkoSource=pekko://EventGenerator/system/sharding/shopping-cart-event/903/6059e,
sourceActorSystem=EventGenerator, persistenceId=6059e}
```
Run the first member of your new Pekko cluster:
@@ -82,13 +82,13 @@ mvn compile exec:java
-Dexec.mainClass="jdocs.guide.ShoppingCartClusterApp" -Dex
When the app is running you will observe that it will process all the shopping
cart event tags, because it's the only member of the cluster.
```
-[2020-08-13 15:03:39,809] [INFO] [docs.guide.ItemPopularityProjectionHandler]
[] [ShoppingCartClusterApp-org.apache.pekko.actor.default-dispatcher-43] -
ItemPopularityProjectionHandler(carts-1) item popularity for 'pekko t-shirt':
[1080] MDC: {}
-[2020-08-13 15:03:39,810] [INFO] [docs.guide.ItemPopularityProjectionHandler]
[] [ShoppingCartClusterApp-org.apache.pekko.actor.default-dispatcher-40] -
ItemPopularityProjectionHandler(carts-2) item popularity for 'bowling shoes':
[1241] MDC: {}
-[2020-08-13 15:03:39,812] [INFO] [docs.guide.ItemPopularityProjectionHandler]
[] [ShoppingCartClusterApp-org.apache.pekko.actor.default-dispatcher-43] -
ItemPopularityProjectionHandler(carts-0) item popularity for 'pekko t-shirt':
[1080] MDC: {}
+[2020-08-13 15:03:39,809] [INFO] [docs.guide.ItemPopularityProjectionHandler]
[] [ShoppingCartClusterApp-pekko.actor.default-dispatcher-43] -
ItemPopularityProjectionHandler(carts-1) item popularity for 'pekko t-shirt':
[1080] MDC: {}
+[2020-08-13 15:03:39,810] [INFO] [docs.guide.ItemPopularityProjectionHandler]
[] [ShoppingCartClusterApp-pekko.actor.default-dispatcher-40] -
ItemPopularityProjectionHandler(carts-2) item popularity for 'bowling shoes':
[1241] MDC: {}
+[2020-08-13 15:03:39,812] [INFO] [docs.guide.ItemPopularityProjectionHandler]
[] [ShoppingCartClusterApp-pekko.actor.default-dispatcher-43] -
ItemPopularityProjectionHandler(carts-0) item popularity for 'pekko t-shirt':
[1080] MDC: {}
...
```
-Run a second member to expand the Pekko cluster member count to 2.
+Run a second member to expand the Apache Pekko cluster member count to 2.
<!-- run from repo:
sbt "examples/test:runMain docs.guide.ShoppingCartClusterApp 7335"
@@ -111,26 +111,26 @@ mvn compile exec:java
-Dexec.mainClass="jdocs.guide.ShoppingCartClusterApp" -Dex
When the second app is running you will observe a sharding rebalance complete
and then see a distinct set of tagged events processed on each cluster member.
-A rebalance occurs and tag `carts-0` is assigned to the new cluster member.
+A rebalance occurs and tag `carts-0` is assigned to the new cluster member.
Only tags `carts-1` and `carts-2` are processed by the first member.
```
-[2020-08-13 15:03:59,019] [INFO]
[org.apache.pekko.cluster.sharding.DDataShardCoordinator] []
[ShoppingCartClusterApp-pekko.actor.default-dispatcher-41] - Starting rebalance
for shards [0]. Current shards rebalancing: [] MDC:
{pekkoAddress=pekko://ShoppingCa
[email protected]:7334,
sourceThread=ShoppingCartClusterApp-pekko.actor.default-dispatcher-44,
pekkoSource=pekko://[email protected]:7334/system/sharding/sharded-daemon-process-shopping-cartsCoordinator/singleton/coordinator,
-sourceActorSystem=ShoppingCartClusterApp, akkaTimestamp=19:03:59.019UTC}
-[2020-08-13 15:04:35,261] [INFO] [docs.guide.ItemPopularityProjectionHandler]
[] [ShoppingCartClusterApp-pekko.actor.default-dispatcher-43] -
ItemPopularityProjectionHandler(carts-1) item popularity for 'skis': [1244]
MDC: {}
-[2020-08-13 15:04:36,802] [INFO] [docs.guide.ItemPopularityProjectionHandler]
[] [ShoppingCartClusterApp-pekko.actor.default-dispatcher-40] -
ItemPopularityProjectionHandler(carts-2) item popularity for 'skis': [1246]
MDC: {}
-[2020-08-13 15:04:36,805] [INFO] [docs.guide.ItemPopularityProjectionHandler]
[] [ShoppingCartClusterApp-pekko.actor.default-dispatcher-40] -
ItemPopularityProjectionHandler(carts-2) item popularity for 'pekko t-shirt':
[1136] MDC: {}
-[2020-08-13 15:04:36,807] [INFO] [docs.guide.ItemPopularityProjectionHandler]
[] [ShoppingCartClusterApp-pekko.actor.default-dispatcher-43] -
ItemPopularityProjectionHandler(carts-2) item popularity for 'skis': [1249]
MDC: {}
-[2020-08-13 15:04:39,262] [INFO] [docs.guide.ItemPopularityProjectionHandler]
[] [ShoppingCartClusterApp-pekko.actor.default-dispatcher-41] -
ItemPopularityProjectionHandler(carts-1) item popularity for 'cat t-shirt':
[1239] MDC: {}
+[2020-08-13 15:03:59,019] [INFO] [Apache
Pekko.cluster.sharding.DDataShardCoordinator] []
[ShoppingCartClusterApp-pekko.actor.default-dispatcher-41] - Starting rebalance
for shards [0]. Current shards rebalancing: [] MDC:
{pekkoAddress=pekko://ShoppingCa
[email protected]:7334,
sourceThread=ShoppingCartClusterApp-pekko.actor.default-dispatcher-44,
pekkoSource=pekko://[email protected]:7334/system/sharding/sharded-daemon-process-shopping-cartsCoordinator/singleton/coordinator,
+sourceActorSystem=ShoppingCartClusterApp, pekkoTimestamp=19:03:59.019UTC}
+[2020-08-13 15:04:35,261] [INFO] [docs.guide.ItemPopularityProjectionHandler]
[] [ShoppingCartClusterApp-pekko.actor.default-dispatcher-43] -
ItemPopularityProjectionHandler(carts-1) item popularity for 'skis': [1244]
MDC: {}
+[2020-08-13 15:04:36,802] [INFO] [docs.guide.ItemPopularityProjectionHandler]
[] [ShoppingCartClusterApp-pekko.actor.default-dispatcher-40] -
ItemPopularityProjectionHandler(carts-2) item popularity for 'skis': [1246]
MDC: {}
+[2020-08-13 15:04:36,805] [INFO] [docs.guide.ItemPopularityProjectionHandler]
[] [ShoppingCartClusterApp-pekko.actor.default-dispatcher-40] -
ItemPopularityProjectionHandler(carts-2) item popularity for 'pekko t-shirt':
[1136] MDC: {}
+[2020-08-13 15:04:36,807] [INFO] [docs.guide.ItemPopularityProjectionHandler]
[] [ShoppingCartClusterApp-pekko.actor.default-dispatcher-43] -
ItemPopularityProjectionHandler(carts-2) item popularity for 'skis': [1249]
MDC: {}
+[2020-08-13 15:04:39,262] [INFO] [docs.guide.ItemPopularityProjectionHandler]
[] [ShoppingCartClusterApp-pekko.actor.default-dispatcher-41] -
ItemPopularityProjectionHandler(carts-1) item popularity for 'cat t-shirt':
[1239] MDC: {}
...
```
When the second member joins the cluster it is assigned tag `carts-0` and
begins processing events beginning from the last successfully processed offset.
```
-[2020-08-13 15:04:02,692] [INFO] [docs.guide.ItemPopularityProjectionHandler]
[] [ShoppingCartClusterApp-pekko.actor.default-dispatcher-5] -
ItemPopularityProjectionHandler(carts-0) item popularity for 'bowling shoes':
[1275] MDC: {}
-[2020-08-13 15:04:02,695] [INFO] [docs.guide.ItemPopularityProjectionHandler]
[] [ShoppingCartClusterApp-pekko.actor.default-dispatcher-40] -
ItemPopularityProjectionHandler(carts-0) item popularity for 'pekko t-shirt':
[1110] MDC: {}
+[2020-08-13 15:04:02,692] [INFO] [docs.guide.ItemPopularityProjectionHandler]
[] [ShoppingCartClusterApp-pekko.actor.default-dispatcher-5] -
ItemPopularityProjectionHandler(carts-0) item popularity for 'bowling shoes':
[1275] MDC: {}
+[2020-08-13 15:04:02,695] [INFO] [docs.guide.ItemPopularityProjectionHandler]
[] [ShoppingCartClusterApp-pekko.actor.default-dispatcher-40] -
ItemPopularityProjectionHandler(carts-0) item popularity for 'pekko t-shirt':
[1110] MDC: {}
[2020-08-13 15:04:02,699] [INFO] [docs.guide.ItemPopularityProjectionHandler]
[] [ShoppingCartClusterApp-pekko.actor.default-dispatcher-40] -
ItemPopularityProjectionHandler(carts-0) item popularity for 'cat t-shirt':
[1203] MDC: {}
...
```
diff --git a/docs/src/main/paradox/getting-started/running.md
b/docs/src/main/paradox/getting-started/running.md
index 4bdd1d21..b66cb58e 100644
--- a/docs/src/main/paradox/getting-started/running.md
+++ b/docs/src/main/paradox/getting-started/running.md
@@ -2,7 +2,7 @@
@@@ note
-This example requires a Cassandra database to run.
+This example requires a Cassandra database to run.
If you do not have a Cassandra database then you can run one locally as a
Docker container.
To run a Cassandra database locally you can use [`docker
compose`](https://docs.docker.com/compose/) to run the
[`docker-compose.yml`](https://raw.githubusercontent.com/apache/pekko-projection/main/docker-compose.yml)
found in the Projections project root.
The `docker-compose.yml` file references the latest [Cassandra Docker
Image](https://hub.docker.com/_/cassandra).
@@ -41,11 +41,11 @@ PRIMARY KEY (item_id));
```
Source events are generated with the `EventGeneratorApp`.
-This app is configured to use [Apache Pekko Persistence
Cassandra](https://pekko.apache.org/docs/pekko-persistence-cassandra/current/index.html)
and [Apache Pekko
Cluster](https://pekko.apache.org/docs/pekko/current/typed/cluster.html)
[Sharding](https://pekko.apache.org/docs/pekko/current/typed/cluster-sharding.html)
to persist random `ShoppingCartApp.Events` to a journal.
+This app is configured to use [Apache Pekko Persistence
Cassandra](https://pekko.apache.org/docs/pekko-persistence-cassandra/current/index.html)
and @extref:[Apache Pekko Cluster](pekko:typed/cluster.html)
@extref:[Sharding](pekko:typed/cluster-sharding.html) to persist random
`ShoppingCartApp.Events` to a journal.
It will checkout a shopping cart with random items and quantities every 1
second.
The app will automatically create all the Apache Pekko Persistence
infrastructure tables in the `pekko` keyspace.
We won't go into any further detail about how this app functions because it
falls outside the scope of Apache Pekko Projections.
-To learn more about the writing events with [Apache Pekko Persistence see the
Apache Pekko
documentation](https://pekko.apache.org/docs/pekko/current/typed/index-persistence.html).
+To learn more about the writing events with @extref:[Apache Pekko Persistence
see the Apache Pekko documentation](pekko:typed/index-persistence.html).
Add the Apache Pekko Cluster Sharding library to your project:
diff --git a/docs/src/main/paradox/getting-started/setup-your-app.md
b/docs/src/main/paradox/getting-started/setup-your-app.md
index 8587bafe..4fc162d9 100644
--- a/docs/src/main/paradox/getting-started/setup-your-app.md
+++ b/docs/src/main/paradox/getting-started/setup-your-app.md
@@ -19,7 +19,7 @@ Java
: @@snip
[ShoppingCartEvents.java](/examples/src/test/java/jdocs/guide/ShoppingCartEvents.java)
{ #guideEvents }
To enable serialization and deserialization of events with Apache Pekko
Persistence it's necessary to define a base type for your event type hierarchy.
-In this guide we are using [Jackson
Serialization](https://pekko.apache.org/docs/pekko/current/serialization-jackson.html).
+In this guide we are using @extref:[Jackson
Serialization](pekko:serialization-jackson.html).
Add the `CborSerializable` base type to your project:
Scala
@@ -40,12 +40,12 @@ Java
@@@ note
For Jackson serialization to work correctly in Java projects you must use the
`javac` compiler parameter `-parameters` when building your project.
-In @scala[sbt you can add it your sbt project by adding it to the
`javacOptions` Setting: `javacOptions += "-parameters"`]@java[maven you can add
an argument to `maven-compiler-plugin` plugin under `compilerArgs`].
+In @scala[sbt you can add it your sbt project by adding it to the
`javacOptions` Setting: `javacOptions += "-parameters"`]@java[maven you can add
an argument to `maven-compiler-plugin` plugin under `compilerArgs`.
@@@
Define the persistence tags to be used in your project.
-Note that partitioned tags will be used later when @ref[running the projection
in Apache Pekko Cluster](running-cluster.md).
+Note that partitioned tags will be used later when @ref[running the projection
in an Apache Pekko Cluster](running-cluster.md).
Add `ShoppingCartTags` to your project:
Scala
@@ -54,8 +54,8 @@ Scala
Java
: @@snip
[ShoppingCartTags.java](/examples/src/test/java/jdocs/guide/ShoppingCartTags.java)
{ #guideTags }
-Create the `ShoppingCartApp` with an
`org.apache.pekko.actor.typed.ActorSystem` (API:
@apidoc[pekko.actor.typed.ActorSystem]) for Projections to use.
-Create an empty [Guardian
Actor](https://pekko.apache.org/docs/pekko/current/typed/actor-lifecycle.html#the-guardian-actor)
(the root Actor of the `ActorSystem`).
+Create the `ShoppingCartApp` with an `pekko.actor.typed.ActorSystem` (API:
@apidoc[pekko.actor.typed.ActorSystem]) for Projections to use.
+Create an empty @extref:[Guardian
Actor](pekko:typed/actor-lifecycle.html#the-guardian-actor) (the root Actor of
the `ActorSystem`).
We will populate this Actor in the following steps of the guide.
Note that we are using the @scala[`docs.scaladsl`]@java[`jdocs.scaladsl`]
package.
You may use any package, but we include this package in snippets throughout
the guide.
diff --git a/docs/src/main/paradox/getting-started/source-provider.md
b/docs/src/main/paradox/getting-started/source-provider.md
index 35d9bc89..ab94520d 100644
--- a/docs/src/main/paradox/getting-started/source-provider.md
+++ b/docs/src/main/paradox/getting-started/source-provider.md
@@ -1,6 +1,6 @@
# Choosing a Source Provider
-A @apidoc[SourceProvider] will provide the data to our projection.
+A @apidoc[SourceProvider] will provide the data to our projection.
In Projections each element that's processed is an `Envelope` and each
`Envelope` contains an `Event`.
An `Envelope` must include an `Offset`, but it can also contain other
information such as creation timestamp, a topic name, an entity tag, etc.
There are several supported Source Provider's available (or you can build your
own), but in this example we will use the @ref:[Apache Pekko Persistence
`EventSourced` Source Provider](../eventsourced.md).
@@ -22,7 +22,7 @@ Java
: @@snip
[ShoppingCartApp.java](/examples/src/test/java/jdocs/guide/ShoppingCartApp.java)
{ #guideSourceProviderImports }
Create the @apidoc[SourceProvider].
-The @ref:[Event Sourced Source Provider](../eventsourced.md) is using [Apache
Pekko
Persistence](https://pekko.apache.org/docs/pekko/current/typed/persistence.html)
internally (specifically the
[eventsByTag](https://pekko.apache.org/docs/pekko/current/persistence-query.html#eventsbytag-and-currenteventsbytag)
API).
+The @ref:[Event Sourced Source Provider](../eventsourced.md) is using
@extref:[Apache Pekko Persistence](pekko:typed/persistence.html) internally
(specifically the
@extref:[eventsByTag](pekko:persistence-query.html#eventsbytag-and-currenteventsbytag)
API).
To initialize the Source Provider we need to set parameters to choose the
Apache Pekko Persistence plugin (Cassandra) to use as well as the name of the
tag used for events we're interested in from the journal.
Setup the `SourceProvider` in the Guardian `Behavior` defined in
`ShoppingCartApp`:
diff --git a/docs/src/main/paradox/getting-started/testing.md
b/docs/src/main/paradox/getting-started/testing.md
index fd1e3e38..58d2466d 100644
--- a/docs/src/main/paradox/getting-started/testing.md
+++ b/docs/src/main/paradox/getting-started/testing.md
@@ -9,9 +9,9 @@ artifact=pekko-projection-testkit_$scala.binary.version$
version=$project.version$
}
-Import the
@apidoc[pekko.projection.testkit.(javadsl|scaladsl).ProjectionTestKit] and
other utilities into a new
-@scala[[ScalaTest](https://pekko.apache.org/docs/pekko/current/typed/testing-async.html#test-framework-integration)
test spec]
-@java[[JUnit](https://pekko.apache.org/docs/pekko/current/typed/testing-async.html#test-framework-integration)
test].
+Import the
@apidoc[pekko.projection.testkit.(javadsl|scaladsl).ProjectionTestKit] and
other utilities into a new
+@scala:[[ScalaTest](pekko:typed/testing-async.html#test-framework-integration)
test spec]
+@java:[[JUnit](pekko:typed/testing-async.html#test-framework-integration)
test].
Scala
: @@snip
[ShoppingCartAppSpec.scala](/examples/src/test/scala/docs/guide/ShoppingCartAppSpec.scala)
{ #testKitImports }
diff --git a/docs/src/main/paradox/grpc-replicated-event-sourcing-transport.md
b/docs/src/main/paradox/grpc-replicated-event-sourcing-transport.md
new file mode 100644
index 00000000..659789c8
--- /dev/null
+++ b/docs/src/main/paradox/grpc-replicated-event-sourcing-transport.md
@@ -0,0 +1,185 @@
+# Pekko Replicated Event Sourcing over gRPC
+
+Pekko Replicated Event Sourcing extends Pekko Persistence allowing multiple
replicas of the same entity, all accepting
+writes, for example in different data centers or cloud provider regions. This
makes it possible to implement patterns
+such as active-active and hot standby.
+
+Originally, Pekko Replicated Event Sourcing has required cross-replica access
to the underlying replica database, which
+can be hard to open up for security and infrastructure reasons. It was also
easiest to use in an
+:[Apache Pekko Multi DC Cluster](pekko:typed/cluster-dc.html) setup
+where a single cluster spans multiple datacenters or regions, another thing
that can be complicated to allow.
+
+Pekko Replicated Event Sourcing over gRPC builds on @ref:[Apache Pekko
Projection gRPC](grpc.md) and @extref:[Apache Pekko
gRPC](pekko-grpc:index.html) to instead use gRPC as the cross-replica transport
for events.
+
+There are no requirements that the replicas are sharing a cluster, instead it
is expected that each replica is a separate
+Pekko cluster with the gRPC replication transport as only connection in
between.
+
+@@@ warning
+
+This module is currently marked as @extref:[May
Change](pekko:common/may-change.html)
+in the sense that the API might be changed based on feedback from initial
usage.
+However, the module is ready for usage in production and we will not break
serialization format of
+messages or stored data.
+
+@@@
+
+## Overview
+
+For a basic overview of Replicated Event Sourcing see the @extref:[Apache
Pekko Replicated Event Sourcing docs](pekko:typed/replicated-eventsourcing.html)
+
+Pekko Replicated Event Sourcing over gRPC consists of the following three
parts:
+
+* The Replicated Event Sourced Behavior is run in each replica as a sharded
entity using @extref:[Apache Pekko Cluster
+ Sharding](pekko:typed/cluster-sharding.html).
+
+* The events of each replica are published to the other replicas using
@ref:[Apache Pekko Projection gRPC](grpc.md) endpoints.
+
+* Each replica consumes a number of parallel slices of the events from each
other replica by running Pekko Projection
+ gRPC in @extref:[Apache Pekko Sharded Daemon
Process](pekko:typed/cluster-sharded-daemon-process.html).
+
+
+## Dependencies
+
+The functionality is provided through the `pekko-projection-grpc` module.
+
+@@project-info{ projectId="grpc" }
+
+To use the gRPC module of Apache Pekko Projections add the following
dependency in your project:
+
+@@dependency [sbt,Maven,Gradle] {
+ group=org.apache.pekko
+ artifact=pekko-projection-grpc_$scala.binary.version$
+ version=$project.version$
+}
+
+Pekko Replicated Event Sourcing over gRPC can only be run in an Apache Pekko
cluster since it uses cluster components.
+
+It is currently only possible to use @ref:[Apache
Pekko-projection-r2dbc](r2dbc.md) as the
+projection storage and journal for this module.
+
+The full set of dependencies needed:
+
+@@dependency [sbt,Maven,Gradle] {
+group=org.apache.pekko
+artifact=pekko-projection-grpc_$scala.binary.version$
+version=$project.version$
+group2=org.apache.pekko
+artifact2=pekko-cluster-typed_$scala.binary.version$
+version2=$pekko.version$
+group3=org.apache.pekko
+artifact3=pekko-cluster-sharding-typed_$scala.binary.version$
+version3=$pekko.version$
+group4=org.apache.pekko
+artifact4=pekko-persistence-r2dbc_$scala.binary.version$
+version4=$pekko.r2dbc.version$
+group5=org.apache.pekko
+artifact5=pekko-projection-r2dbc_$scala.binary.version$
+version5=$pekko.r2dbc.version$
+}
+
+### Transitive dependencies
+
+The table below shows `pekko-projection-grpc`'s direct dependencies, and the
second tab shows all libraries it depends on transitively.
+
+@@dependencies{ projectId="grpc" }
+
+## API and setup
+
+The same API as regular `EventSourcedBehavior`s is used to define the logic.
See @extref:[Replicated Event
Sourcing](pekko:typed/replicated-eventsourcing.html) for more detail on
designing an entity for replication.
+
+To enable an entity for Replicated Event Sourcing over gRPC, use the
@apidoc[Replication$] `grpcReplication` method,
+which takes @apidoc[ReplicationSettings], a factory function for the behavior,
and an actor system.
+
+The factory function will be passed a @apidoc[ReplicatedBehaviors] factory
that must be used to set up the replicated
+event sourced behavior. Its `setup` method provides a
@apidoc[ReplicationContext] to create an `EventSourcedBehavior`
+which will then be configured for replication. The behavior factory can be
composed with other behavior factories, if
+access to the actor context or timers are needed.
+
+### Settings
+
+The @apidoc[pekko.projection.grpc.replication.*.ReplicationSettings]
@scala[`apply`]@java[`create`] factory methods can
+accept an entity name, a @apidoc[ReplicationProjectionProvider] and an actor
system. The configuration of that system
+is expected to have a top level entry with the entity name containing this
structure:
+
+Scala
+: @@snip
[config](/grpc-test/src/test/scala/org/apache/pekko/projection/grpc/replication/ReplicationSettingsSpec.scala)
{ #config }
+
+Java
+: @@snip
[config](/grpc-test/src/test/scala/org/apache/pekko/projection/grpc/replication/ReplicationSettingsSpec.scala)
{ #config }
+
+The entries in the block refer to the local replica while `replicas` is a list
of all replicas, including the node itself,
+with details about how to reach the replicas across the network.
+
+The `grpc.client` section for each of the replicas is used for setting up the
Apache Pekko gRPC client and supports the same discovery, TLS
+and other connection options as when using Apache Pekko gRPC directly. For
more details see @extref:[Apache Pekko gRPC
configuration](pekko-grpc:client/configuration.html#by-configuration).
+
+It is also possible to set up
@apidoc[pekko.projection.grpc.replication.*.ReplicationSettings] through APIs
only and not rely
+on the configuration file at all.
+
+### Binding the publisher
+
+Binding the publisher is a manual step to allow arbitrary customization of the
Apache Pekko HTTP server and combining the endpoint
+with other HTTP and gRPC routes.
+
+When there is only a single replicated entity and no other usage of Apache
Pekko gRPC Projections in an application a
+convenience is provided through `createSingleServiceHandler` on
@apidoc[pekko.projection.grpc.replication.*.Replication]
+which will create a single handler.
+
+When multiple producers exist, all instances of
@apidoc[pekko.projection.grpc.producer.EventProducerSettings] need to
+be passed at once to `EventProducer.grpcServiceHandler` to create a single
producer service handling each of the event
+streams.
+
+Scala
+: @@snip
[ProducerApiSample.scala](/grpc-test/src/test/scala/org/apache/pekko/projection/grpc/replication/scaladsl/ProducerApiSample.scala)
{ #multi-service }
+
+Java
+: @@snip
[ReplicationCompileTest.java](/grpc-test/src/test/java/org/apache/pekko/projection/grpc/replication/javdsl/ReplicationCompileTest.java)
{ #multi-service }
+
+
+The Pekko HTTP server must be running with HTTP/2. This is the default since
Pekko HTTP 2.0.0.
+
+### Serialization of events
+
+The events are serialized for being passed over the wire using the same Pekko
serializer as configured for serializing
+the events for storage.
+
+Note that having separate replicas increases the risk that two different
serialized formats and versions of the serializer
+are running at the same time, so extra care must be taken when changing the
events and their serialization and deploying
+new versions of the application to the replicas.
+
+For some scenarios it may be necessary to do a two-step deploy of format
changes to not lose data, first deploy support
+for a new serialization format so that all replicas can deserialize it, then a
second deploy where the new field is actually
+populated with data.
+
+## Filters
+
+By default, events from all Replicated Event Sourced entities are replicated.
+
+The same kind of filters as described in @ref:[Apache Pekko Projection gRPC
Filters](grpc.md#filters) can be used for
+Replicated Event Sourcing.
+
+Consumer defined filters are updated as described in @ref:[Apache Pekko
Projection gRPC Consumer defined filter](grpc.md#consumer-defined-filter)
+
+One thing to note is that `streamId` is always the same as the `entityType`
when using Replicated Event Sourcing.
+
+The entity id based filter criteria must include the replica id as suffix to
the entity id, with `|` separator.
+
+Replicated Event Sourcing is bidirectional replication, and therefore you
would typically have to define the same
+filters on both sides. That is not handled automatically.
+
+## Sample projects
+
+Source code and build files for complete sample projects can be found in the
`apache/pekko-projection` GitHub repository.
+
+
+## Access control
+
+### From the consumer
+
+The consumer can pass metadata, such as auth headers, in each request to the
producer service by specifying @apidoc[pekko.grpc.*.Metadata] as
`additionalRequestMetadata` when creating each
@apidoc[pekko.projection.grpc.replication.*.Replica]
+
+### In the producer
+
+Authentication and authorization for the producer can be done by implementing
an @apidoc[EventProducerInterceptor] and passing
+it to the `grpcServiceHandler` method during producer bootstrap. The
interceptor is invoked with the stream id and
+gRPC request metadata for each incoming request and can return a suitable
error through @apidoc[GrpcServiceException]
diff --git a/docs/src/main/paradox/grpc.md b/docs/src/main/paradox/grpc.md
index 733a2beb..7722452d 100644
--- a/docs/src/main/paradox/grpc.md
+++ b/docs/src/main/paradox/grpc.md
@@ -1,12 +1,12 @@
-# Apache Pekko Projection gRPC
+# Pekko Projection gRPC
-Apache Pekko Projection gRPC can be used for implementing asynchronous event
based service-to-service communication.
-It provides an implementation of a Pekko Projection that uses
-[Pekko gRPC](https://pekko.apache.org/docs/pekko-grpc/current/index.html) as
underlying transport between event producer and consumer.
+Pekko Projection gRPC can be used for implementing asynchronous event based
service-to-service communication.
+It provides an implementation of an Apache Pekko Projection that uses
+@extref:[Apache Pekko gRPC](pekko-grpc:index.html) as underlying transport
between event producer and consumer.
@@@ warning
-This module is currently marked as [May
Change](https://pekko.apache.org/docs/pekko/current/common/may-change.html)
+This module is currently marked as @extref:[May
Change](pekko:common/may-change.html)
in the sense that the API might be changed based on feedback from initial
usage.
However, the module is ready for usage in production and we will not break
serialization format of
messages or stored data.
@@ -18,7 +18,7 @@ messages or stored data.

1. An Entity stores events in its journal in service A.
-1. Consumer in service B starts a Pekko Projection which locally reads its
offset for service A's replication stream.
+1. Consumer in service B starts an Apache Pekko Projection which locally reads
its offset for service A's replication stream.
1. Service B establishes a replication stream from service A.
1. Events are read from the journal.
1. Event is emitted to the replication stream.
@@ -40,6 +40,17 @@ Apache Pekko Projections require Pekko $pekko.version$ or
later, see @ref:[Pekko
@@project-info{ projectId="grpc" }
+It is currently only possible to use @extref:[Apache
Pekko-persistence-r2dbc](pekko-persistence-r2dbc:projection.html) as the
+projection storage and journal for this module.
+
+@@dependency [sbt,Maven,Gradle] {
+group=org.apache.pekko
+artifact=pekko-persistence-r2dbc_$scala.binary.version$
+version=$pekko.r2dbc.version$
+group2=org.apache.pekko
+artifact2=pekko-projection-r2dbc_$scala.binary.version$
+version2=$pekko.r2dbc.version$
+}
### Transitive dependencies
@@ -60,18 +71,18 @@ and not from configuration via `GrpcReadJournalProvider`
when using Protobuf ser
The gRPC connection to the producer is defined in the [consumer
configuration](#consumer-configuration).
-The
[R2dbcProjection](https://pekko.apache.org/docs/pekko-persistence-r2dbc/current/projection.html)
has support for storing the offset in a relational database using R2DBC.
+The @extref:[R2dbcProjection](pekko-persistence-r2dbc:projection.html) has
support for storing the offset in a relational database using R2DBC.
-One approach is to use the
[ShardedDaemonProcess](https://pekko.apache.org/docs/pekko/current/typed/cluster-sharded-daemon-process.html)
to distribute the instances of the Projection across the cluster.
+The above example is using the
@extref:[ShardedDaemonProcess](pekko:typed/cluster-sharded-daemon-process.html)
to distribute the instances of the Projection across the cluster.
There are alternative ways of running the `ProjectionBehavior` as described in
@ref:[Running a Projection](running.md)
-How to implement the `EventHandler` and choose between different processing
semantics is described in the [R2dbcProjection
documentation](https://pekko.apache.org/docs/pekko-persistence-r2dbc/current/projection.html).
+How to implement the `EventHandler` and choose between different processing
semantics is described in the @extref:[R2dbcProjection
documentation](pekko-persistence-r2dbc:projection.html).
### gRPC client lifecycle
-When creating the @apidoc[GrpcReadJournal] a gRPC client is created for the
target producer. The same `GrpcReadJournal`
-instance and its gRPC client should be shared for the same target producer.
The code examples will share the instance
-between different Projection instances running in the same `ActorSystem`. The
gRPC clients will automatically be
+When creating the @apidoc[GrpcReadJournal] a gRPC client is created for the
target producer. The same `GrpcReadJournal`
+instance and its gRPC client should be shared for the same target producer.
The code examples above will share the instance
+between different Projection instances running in the same `ActorSystem`. The
gRPC clients will automatically be
closed when the `ActorSystem` is terminated.
If there is a need to close the gRPC client before `ActorSystem` termination
the `close()` method of the @apidoc[GrpcReadJournal]
@@ -83,11 +94,134 @@ Apache Pekko Projections gRPC provides the gRPC service
implementation that is u
Events can be transformed by application specific code on the producer side.
The purpose is to be able to have a
different public representation from the internal representation (stored in
journal). The transformation functions
-are registered when creating the `EventProducer` service.
+are registered when creating the `EventProducer` service. Here is an example
of one of those transformation functions
+accessing the projection envelope to include the shopping cart id in the
public message type passed to consumers.
To omit an event the transformation function can return
@scala[`None`]@java[`Optional.empty()`].
-That `EventProducer` service is started in a Pekko gRPC server.
+That `EventProducer` service is started in an Apache Pekko gRPC server.
+
+The Pekko HTTP server must be running with HTTP/2. This is the default since
Pekko HTTP 2.0.0.
+
+This example includes an application specific `ShoppingCartService`, which is
unrelated to Pekko Projections gRPC,
+but it illustrates how to combine the `EventProducer` service with other gRPC
services.
+
+## Filters
+
+By default, events from all entities of the given entity type and slice range
are emitted from the producer to the
+consumer. The transformation function on the producer side can omit certain
events, but the offsets for these
+events are still transferred to the consumer, to ensure sequence number
validations and offset storage.
+
+Filters can be used when a consumer is only interested in a subset of the
entities. The filters can be defined
+on both the producer side and on the consumer side, and they can be changed at
runtime.
+
+### Tags
+
+Tags are typically used for the filters, so first an example of how to tag
events in the entity. Here, the tag is
+based on total quantity of the shopping cart, i.e. the state of the cart. The
tags are included in the
+@apidoc[pekko.persistence.query.typed.EventEnvelope].
+
+### Producer defined filter
+
+The producer may define a filter function on the `EventProducerSource`.
+
+In this example the decision is based on tags, but the filter function can use
anything in the
+@apidoc[pekko.persistence.query.typed.EventEnvelope] parameter or the event
itself. Here, the entity sets the tag based
+on the total quantity of the shopping cart, which requires the full state of
the shopping cart and is not known from
+an individual event.
+
+Note that the purpose of the `withProducerFilter` is to toggle if all events
for the entity are to be emitted or not.
+If the purpose is to filter out certain events you should instead use the
`Transformation`.
+
+The producer filter is evaluated before the transformation function, i.e. the
event is the original event and not
+the transformed event.
+
+A producer filter that excludes an event wins over any consumer defined
filter, i.e. if the producer filter function
+returns `false` the event will not be emitted.
+
+### Consumer defined filter
+
+The consumer may define declarative filters that are sent to the producer and
evaluated on the producer side
+before emitting the events.
+
+Consumer filters consists of exclude and include criteria. In short, the
exclude criteria are evaluated first and
+may be overridden by an include criteria. More precisely, they are evaluated
according to the following rules:
+
+* Exclude criteria are evaluated first.
+* If no matching exclude criteria the event is emitted.
+* If an exclude criteria is matching the include criteria are evaluated.
+* If no matching include criteria the event is discarded.
+* If matching include criteria the event is emitted.
+
+The exclude criteria can be a combination of:
+
+* `ExcludeTags` - exclude events with any of the given tags
+* `ExcludeRegexEntityIds` - exclude events for entities with entity ids
matching the given regular expressions
+* `ExcludeEntityIds` - exclude events for entities with the given entity ids
+
+To exclude all events you can use `ExcludeRegexEntityIds` with `.*`.
+
+The exclude criteria can be a combination of:
+
+* `IncludeTags` - include events with any of the given tags
+* `IncludeRegexEntityIds` - include events for entities with entity ids
matching the given regular expressions
+* `IncludeEntityIds` - include events for entities with the given entity ids
+
+The filter is updated with the @apidoc[ConsumerFilter] extension.
+
+Note that the `streamId` must match what is used when initializing the
`GrpcReadJournal`, which by default is from
+the config property `pekko.projection.grpc.consumer.stream-id`.
+
+The filters can be dynamically changed in runtime without restarting the
Projections or the `GrpcReadJournal`. The
+updates are incremental. For example if you first add an `IncludeTags` of tag
`"medium"` and then update the filter
+with another `IncludeTags` of tag `"large"`, the full filter consists of both
`"medium"` and `"large"`.
+
+To remove a filter criteria you would use the corresponding
@apidoc[ConsumerFilter.RemoveCriteria], for example
+`RemoveIncludeTags`.
+
+The updated filter is kept and remains after restarts of the Projection
instances. If the consumer side is
+running with Apache Pekko Cluster the filter is propagated to other nodes in
the cluster automatically with
+Pekko Distributed Data. You only have to update at one place and it will be
applied to all running Projections
+with the given `streamId`.
+
+@@@ warning
+The filters will be cleared in case of a full Cluster stop, which means that
you
+need to take care of populating the initial filters at startup.
+@@@
+
+See @apidoc[ConsumerFilter] for full API documentation.
+
+### Event replay
+
+When the consumer receives an event that is not the first event for the
entity, and it hasn't processed and stored
+the offset for the preceding event (previous sequence number) a replay of
previous events will be triggered.
+The reason is that the consumer is typically interested in all events for an
entity and must process them in
+the original order. Even though this is completely automatic it can be good to
be aware of since it may have
+a substantial performance impact to replay many events for many entities.
+
+The event replay is triggered "lazily" when a new event with unexpected
sequence number is received, but with
+the `ConsumerFilter.IncludeEntityIds` it is possible to explicitly define a
sequence number from which the
+replay will start immediately. You have the following choices for the sequence
number in the `IncludeEntityIds`
+criteria:
+
+* if the previously processed sequence number is known, the next (+1) sequence
number can be defined
+* `1` can be used to for replaying all events of the entity
+* `0` can be used to not replay events immediately, but they will be replayed
lazily as described previously
+
+Any duplicate events are filtered out by the Projection on the consumer side.
This deduplication mechanism depends
+on how long the Projection will keep old offsets. You may have to increase the
configuration for this, but that has
+the drawback of more memory usage.
+
+```
+pekko.projection.r2dbc.offset-store.time-window = 15 minutes
+```
+
+Application level deduplication of idempotency may be needed if the Projection
can't keep enough offsets in memory.
+
+## Sample projects
+
+Source code and build files for complete sample projects can be found in
`apache/pekko-projection` GitHub repository.
+
## Access control
@@ -98,21 +232,21 @@ The consumer can pass metadata, such as auth headers, in
each request to the pro
### In the producer
Authentication and authorization for the producer can be done by implementing
a @apidoc[EventProducerInterceptor] and pass
-it to the `grpcServiceHandler` method during producer bootstrap. The
interceptor is invoked with the stream id and
-gRPC request metadata for each incoming request and can return a suitable
error through @apidoc[GrpcServiceException]
+it to the `grpcServiceHandler` method during producer bootstrap. The
interceptor is invoked with the stream id and
+gRPC request metadata for each incoming request and can return a suitable
error through @apidoc[pekko.grpc.GrpcServiceException]
## Performance considerations
### Lower latency
-See [Publish events for lower latency of
eventsBySlices](https://pekko.apache.org/docs/pekko-persistence-r2dbc/current/query.html#publish-events-for-lower-latency-of-eventsbyslices)
+See @extref:[Publish events for lower latency of
eventsBySlices](pekko-persistence-r2dbc:query.html#publish-events-for-lower-latency-of-eventsbyslices)
for low latency use cases.
### Scalability limitations
Each connected consumer will start a `eventsBySlices` query that will
periodically poll and read events from the journal.
That means that the journal database will become a bottleneck, unless it can
be scaled out, when number of consumers increase.
-The producer service itself can easily be scaled out to more instances.
+The producer service itself can easily be scaled out to more instances.
For the case of many consumers of the same event stream a future improvement
to reduce the
database load would be to share results of the queries across the different
consumers, since most of them are
@@ -122,7 +256,7 @@ probably reading at the tail of the same event stream.
### Consumer configuration
-The `client` section in the configuration defines where the producer is
running. It is a [Pekko gRPC
configuration](https://pekko.apache.org/docs/pekko-grpc/current/client/configuration.html#by-configuration)
with several connection options.
+The `client` section in the configuration defines where the producer is
running. It is an @extref:[Apache Pekko gRPC
configuration](pekko-grpc:client/configuration.html#by-configuration) with
several connection options.
### Reference configuration
diff --git a/docs/src/main/paradox/index.md b/docs/src/main/paradox/index.md
index 6c07a769..637aa4ba 100644
--- a/docs/src/main/paradox/index.md
+++ b/docs/src/main/paradox/index.md
@@ -9,9 +9,9 @@
* [Getting Started Guide](getting-started/index.md)
* [Event Sourced](eventsourced.md)
* [Durable State](durable-state.md)
-* [Kafka](kafka.md)
+* [Apache Kafka](kafka.md)
* [R2DBC](r2dbc.md)
-* [Cassandra](cassandra.md)
+* [Apache Cassandra](cassandra.md)
* [JDBC](jdbc.md)
* [Slick](slick.md)
* [Running](running.md)
@@ -20,6 +20,7 @@
* [Error](error.md)
* [Projection Settings](projection-settings.md)
* [gRPC](grpc.md)
+* [Replicated Event Sourcing over
gRPC](grpc-replicated-event-sourcing-transport.md)
* [Management](management.md)
* [Testing](testing.md)
* [Classic](classic.md)
diff --git a/docs/src/main/paradox/jdbc.md b/docs/src/main/paradox/jdbc.md
index e6e36ca3..c504a660 100644
--- a/docs/src/main/paradox/jdbc.md
+++ b/docs/src/main/paradox/jdbc.md
@@ -38,9 +38,9 @@ There are two settings that need to be set beforehand in your
`application.conf`
## Defining a JdbcSession
-Before using Apache Pekko Projections JDBC you must implement a `JdbcSession`
@scala[trait]@java[interface]. `JdbcSession` is used to open a connection and
start a transaction. A new `JdbcSession` will be created for each call to the
handler. At the end of the processing, the transaction will be committed (or
rolled back).
+Before using Apache Pekko Projections JDBC you must implement a `JdbcSession`
@scala[trait]@java[interface]. `JdbcSession` is used to open a connection and
start a transaction. A new `JdbcSession` will be created for each call to the
handler. At the end of the processing, the transaction will be committed (or
rolled back).
-When using `JdbcProjection.exactlyOnce`, the `JdbcSession` that is passed to
the handler will be used to save the offset behind the scenes. Therefore, it's
extremely important to disable auto-commit (eg: `setAutoCommit(false)`),
otherwise the two operations won't participate on the same transaction.
+When using `JdbcProjection.exactlyOnce`, the `JdbcSession` that is passed to
the handler will be used to save the offset behind the scenes. Therefore, it's
extremely important to disable auto-commit (eg: `setAutoCommit(false)`),
otherwise the two operations won't participate on the same transaction.
Scala
: @@snip
[JdbcProjectionDocExample.scala](/examples/src/test/scala/docs/jdbc/JdbcProjectionDocExample.scala)
{ #jdbc-session-imports #jdbc-session }
@@ -58,7 +58,7 @@ When declaring a `JdbcProjection` you must provide a factory
for the `JdbcSessio
An alternative Hibernate based implementation would look like this:
Java
-: @@snip
[HibernateJdbcSession.java](/examples/src/test/java/jdocs/jdbc/HibernateJdbcSession.java)
{ #hibernate-session-imports #hibernate-session }
+: @@snip
[HibernateJdbcSession.java](/examples/src/test/java/jdocs/jdbc/HibernateJdbcSession.java)
{ #hibernate-session-imports #hibernate-session }
And a special factory that initializes the `EntityManagerFactory` and builds
the `JdbcSession` instance:
@@ -68,14 +68,14 @@ Java
## Blocking JDBC Dispatcher
-JDBC APIs are blocking by design, therefore Apache Pekko Projections JDBC will
use a dedicated dispatcher to run all JDBC calls. It's important to configure
the dispatcher to have the same size as the connection pool.
+JDBC APIs are blocking by design, therefore Pekko Projections JDBC will use a
dedicated dispatcher to run all JDBC calls. It's important to configure the
dispatcher to have the same size as the connection pool.
-Each time the projection handler is called one thread and one database
connection will be used. If your connection pool is smaller than the number of
threads, the thread can potentially block while waiting for the connection pool
to provide a connection.
+Each time the projection handler is called one thread and one database
connection will be used. If your connection pool is smaller than the number of
threads, the thread can potentially block while waiting for the connection pool
to provide a connection.
The dispatcher pool size can be configured through the
`pekko.projection.jdbc.blocking-jdbc-dispatcher.thread-pool-executor.fixed-pool-size`
settings. See @ref:[Configuration](#configuration) section below.
@@@ note
-Most applications will use database connections to read data, for instance to
read a projected model upon user request. This means that other parts of the
application will be competing for a connection. It's recommend to configure a
connection pool dedicated to the projections and use a different one in other
parts of the application.
+Most applications will use database connections to read data, for instance to
read a projected model upon user request. This means that other parts of the
application will be competing for a connection. It's recommend to configure a
connection pool dedicated to the projections and use a different one in other
parts of the application.
@@@
## exactly-once
@@ -134,7 +134,7 @@ processing semantics if the projection is restarted from
previously stored offse
## Handler
It's in the @apidoc[JdbcHandler] that you implement the processing of each
envelope. It's essentially a consumer function
-from `(JdbcSession, Envelope)` to @scala[`Unit`]@java[`void`].
+from `(JdbcSession, Envelope)` to @scala[`Unit`]@java[`void`].
A handler that is consuming `ShoppingCart.Event` from `eventsByTag` can look
like this:
@@ -177,13 +177,13 @@ than the one that called `process`.
It is important that the `Handler` instance is not shared between several
`Projection` instances,
because then it would be invoked concurrently, which is not how it is intended
to be used. Each `Projection`
-instance should use a new `Handler` instance.
+instance should use a new `Handler` instance.
@@@
### Async handler
-The @apidoc[Handler] can be used with `JdbcProjection.atLeastOnceAsync` and
+The @apidoc[Handler] can be used with `JdbcProjection.atLeastOnceAsync` and
`JdbcProjection.groupedWithinAsync` if the handler is not storing the
projection result in the database.
The handler could @ref:[send to a Kafka topic](kafka.md#sending-to-kafka) or
integrate with something else.
@@ -192,7 +192,7 @@ Same type of handlers can be used with `JdbcProjection`
instead of `CassandraPro
### Actor handler
-A good alternative for advanced state management is to implement the handler
as an [actor](https://pekko.apache.org/docs/pekko/current/typed/actors.html),
+A good alternative for advanced state management is to implement the handler
as an @extref:[actor](pekko:typed/actors.html),
which is described in @ref:[Processing with Actor](actor.md).
### Flow handler
@@ -229,20 +229,6 @@ H2
The schema can be created and dropped using the methods
`JdbcProjection.createTablesIfNotExists` and
`JdbcProjection.dropTablesIfExists`. This is particularly useful when writting
tests. For production enviornments, we recommend creating the schema before
deploying the application.
-@@@ warning { title=Important }
-As of version 1.1.0, the schema for PostgreSQL and H2 databases has changed.
It now defaults to lowercase table and column names.
-If you have a schema in production, we recommend applying an ALTER table
script to change it accordingly.
-
-Alternatively, you can fallback to the uppercase format. You will also need to
set `pekko.projection.jdbc.offset-store.table` as an uppercase value, as this
setting is now defaulting to lowercase.
-
-```hocon
-pekko.projection.jdbc.offset-store {
- table = "PEKKO_PROJECTION_OFFSET_STORE"
- use-lowercase-schema = false
-}
-```
-@@@
-
## Offset types
The supported offset types of the `JdbcProjection` are:
@@ -263,7 +249,7 @@ The reference configuration file with the default values:
@@snip [reference.conf](/jdbc/src/main/resources/reference.conf) { #config }
@@@ note
-Settings `pekko.projection.jdbc.dialect` and
`pekko.projection.jdbc.blocking-jdbc-dispatcher.thread-pool-executor.fixed-pool-size`
do not have a valid default value. You must configured them in your
`application.conf` file.
+Settings `pekko.projection.jdbc.dialect` and
`pekko.projection.jdbc.blocking-jdbc-dispatcher.thread-pool-executor.fixed-pool-size`
do not have a valid default value. You must configured them in your
`application.conf` file.
-See @ref:[Required Configuration Settings](#required-configuration-settings)
and @ref:[Blocking JDBC Dispatcher](#blocking-jdbc-dispatcher) sections for
details.
+See @ref:[Required Configuration Settings](#required-configuration-settings)
and @ref:[Blocking JDBC Dispatcher](#blocking-jdbc-dispatcher) sections for
details.
@@@
diff --git a/docs/src/main/paradox/kafka.md b/docs/src/main/paradox/kafka.md
index 16305ce5..9d48b3a4 100644
--- a/docs/src/main/paradox/kafka.md
+++ b/docs/src/main/paradox/kafka.md
@@ -1,6 +1,6 @@
# Messages from and to Apache Kafka
-A typical source for Projections is messages from Kafka. Apache Pekko
Projections supports integration with Kafka using [Pekko Connectors
Kafka](https://pekko.apache.org/docs/pekko-connectors-kafka/current/).
+A typical source for Projections is messages from Kafka. Pekko Projections
supports integration with Kafka using [Apache Pekko Connectors
Kafka](https://pekko.apache.org/docs/pekko-connectors-kafka/current/).
The @apidoc[KafkaSourceProvider$] uses consumer group assignments from Kafka
and can resume from offsets stored in a database.
@@ -48,7 +48,7 @@ Scala
Java
: @@snip
[KafkaDocExample.java](/examples/src/test/java/jdocs/kafka/KafkaDocExample.java)
{ #imports #sourceProvider }
-Please consult the [Pekko Connectors Kafka
documentation](https://pekko.apache.org/docs/pekko-connectors-kafka/current/consumer.html)
for
+Please consult the [Apache Pekko Connectors Kafka
documentation](https://pekko.apache.org/docs/pekko-connectors-kafka/current/consumer.html)
for
specifics around the `ConsumerSettings`. The `KafkaSourceProvider` is using
`Consumer.plainPartitionedManualOffsetSource`.
The `Projection` can then be defined as:
@@ -85,7 +85,7 @@ To mitigate that risk, you can increase the value of
`pekko.projection.kafka.rea
## Committing offset in Kafka
-When using the approach of committing the offsets back to Kafka the [Pekko
Connectors Kafka
comittableSource](https://pekko.apache.org/docs/pekko-connectors-kafka/current/consumer.html)
can be used, and Apache Pekko Projections is not needed for that usage.
+When using the approach of committing the offsets back to Kafka the [Apache
Pekko Connectors Kafka
comittableSource](https://pekko.apache.org/docs/pekko-connectors-kafka/current/consumer.html)
can be used, and Apache Pekko Projections is not needed for that usage.
## Sending to Kafka
@@ -109,7 +109,7 @@ Scala
Java
: @@snip
[KafkaDocExample.java](/examples/src/test/java/jdocs/kafka/KafkaDocExample.java)
{ #imports-producer #sendProducer }
-Please consult the [Pekko Connectors Kafka
documentation](https://pekko.apache.org/docs/pekko-connectors-kafka/current/producer.html)
for
+Please consult the [Apache Pekko Connectors Kafka
documentation](https://pekko.apache.org/docs/pekko-connectors-kafka/current/producer.html)
for
specifics around the `ProducerSettings` and `SendProducer`.
The `Projection` is defined as:
diff --git a/docs/src/main/paradox/management.md
b/docs/src/main/paradox/management.md
index 8de80734..f2faebc7 100644
--- a/docs/src/main/paradox/management.md
+++ b/docs/src/main/paradox/management.md
@@ -55,11 +55,11 @@ Java
## Status tracking
-The status of a `Projection` can be tracked by implementing a
@apidoc[StatusObserver] and enable it with
+The status of a `Projection` can be tracked by implementing a
@apidoc[StatusObserver] and enable it with
`withStatusObserver` before running the `Projection`.
The `StatusObserver` is called when errors occur and envelopes are retried or
the projection failed (restarted).
It also has callbacks for processing progress and projection lifecyle.
The intention is that the implementation of the `StatusObserver` would
maintain a view that can be accessed
-from an administrative UI to have an overview of current status of the
projections.
+from an administrative UI to have an overview of current status of the
projections.
diff --git a/docs/src/main/paradox/overview.md
b/docs/src/main/paradox/overview.md
index c42e28a8..39e21dea 100644
--- a/docs/src/main/paradox/overview.md
+++ b/docs/src/main/paradox/overview.md
@@ -2,7 +2,7 @@
The purpose of Apache Pekko Projections is described in @ref:[Use
Cases](use-cases.md).
-In Apache Pekko Projections you process a stream of events or records from a
source to a projected model or external system.
+In Pekko Projections you process a stream of events or records from a source
to a projected model or external system.
Each event is associated with an offset representing the position in the
stream. This offset is used for
resuming the stream from that position when the projection is restarted.
@@ -22,15 +22,6 @@ For the offset storage you can select from:
Those building blocks are assembled into a `Projection`. You can have many
instances of it
@ref:[automatically distributed and run](running.md) in an Apache Pekko
Cluster.
-@@@ warning
-
-This module is currently marked as [May
Change](https://pekko.apache.org/docs/pekko/current/common/may-change.html)
-in the sense that the API might be changed based on feedback from initial
usage.
-However, the module is ready for usage in production and we will not break
serialization format of
-messages or stored data.
-
-@@@
-
To see a complete example of an Apache Pekko Projections implementation review
the @ref:[Getting Started Guide](getting-started/index.md).
## Dependencies
@@ -45,7 +36,7 @@ each module describes which dependency you should define in
your project.
* @ref:[Offset in a relational DB with JDBC](jdbc.md)
* @ref:[Offset in a relational DB with Slick](slick.md) (community-driven
module)
-All of them share a dependency to `pekko-projection-core`:
+All of them share a dependency to `pekko-projection-core`:
@@dependency [sbt,Maven,Gradle] {
group=org.apache.pekko
@@ -57,9 +48,9 @@ All of them share a dependency to `pekko-projection-core`:
### Pekko version
-Apache Pekko Projections requires **Pekko $pekko.version$** or later. See
[Pekko's Binary Compatibility
Rules](https://pekko.apache.org/docs/pekko/current/common/binary-compatibility-rules.html)
for details.
+Apache Pekko Projections requires **Pekko $pekko.version$** or later. See
@extref:[Apache Pekko's Binary Compatibility
Rules](pekko:common/binary-compatibility-rules.html) for details.
-It is recommended to use the latest patch version of Pekko.
+It is recommended to use the latest patch version of Apache Pekko.
It is important all Pekko dependencies are in the same version, so it is
recommended to depend on
them explicitly to avoid problems with transient dependencies causing an
unlucky mix of versions. For example:
@@ -87,13 +78,13 @@ See the individual modules for their transitive
dependencies.
### Pekko Classic
-Apache Pekko Projections can be used with the [new Actor
API](https://pekko.apache.org/docs/pekko/current/typed/actors.html) or
-the [classic Actor
API](https://pekko.apache.org/docs/pekko/current/index-classic.html). The
documentation samples
-show the new Actor API, and the @ref:[Pekko Classic page](classic.md)
highlights how to use it with the classic
+Apache Pekko Projections can be used with the @extref:[new Actor
API](pekko:typed/actors.html) or
+the @extref:[classic Actor API](pekko:index-classic.html). The documentation
samples
+show the new Actor API, and the @ref:[Apache Pekko Classic page](classic.md)
highlights how to use it with the classic
Actor API.
## Contributing
-Please feel free to contribute to Apache Pekko and Apache Pekko Projections by
reporting issues you identify, or by suggesting changes to the code. Please
refer to our [contributing
instructions](https://github.com/apache/pekko/blob/main/CONTRIBUTING.md) to
learn how it can be done.
+Please feel free to contribute to Pekko and Pekko Projections by reporting
issues you identify, or by suggesting changes to the code. Please refer to our
[contributing
instructions](https://github.com/apache/pekko/blob/main/CONTRIBUTING.md) to
learn how it can be done.
We want Pekko to strive in a welcoming and open atmosphere and expect all
contributors to respect our [code of
conduct](https://www.apache.org/foundation/policies/conduct.html).
diff --git a/docs/src/main/paradox/projection-settings.md
b/docs/src/main/paradox/projection-settings.md
index 64ada108..a320d436 100644
--- a/docs/src/main/paradox/projection-settings.md
+++ b/docs/src/main/paradox/projection-settings.md
@@ -1,6 +1,6 @@
# Projection Settings
-A Projection is a background process that continuously consume event envelopes
from a `Source`. Therefore, in case of failures, it is automatically restarted.
This is done by automatically wrapping the `Source` with a [RestartSource with
backoff on
failures](https://pekko.apache.org/docs/pekko/current/stream/operators/RestartSource/onFailuresWithBackoff.html#restartsource-onfailureswithbackoff).
+A Projection is a background process that continuously consume event envelopes
from a `Source`. Therefore, in case of failures, it is automatically restarted.
This is done by automatically wrapping the `Source` with a
@extref:[RestartSource with backoff on
failures](pekko:stream/operators/RestartSource/onFailuresWithBackoff.html#restartsource-onfailureswithbackoff).
By default, the backoff configuration defined in the reference configuration
is used. Those values can be overriden in the `application.conf` file or
programatically as shown below.
diff --git a/docs/src/main/paradox/r2dbc.md b/docs/src/main/paradox/r2dbc.md
index 6cc2f854..34a238d4 100644
--- a/docs/src/main/paradox/r2dbc.md
+++ b/docs/src/main/paradox/r2dbc.md
@@ -16,7 +16,7 @@ that @ref:[exactly-once](#exactly-once) processing semantics
is supported. It al
## Dependencies
-To use the R2DBC module of Pekko Projections add the following dependency in
your project:
+To use the R2DBC module of Apache Pekko Projections add the following
dependency in your project:
@@dependency [Maven,sbt,Gradle] {
group=org.apache.pekko
@@ -27,7 +27,7 @@ artifact2=pekko-persistence-r2dbc_$scala.binary.version$
version2=$pekko.r2dbc.version$
}
-Pekko Projections R2DBC depends on Pekko $pekko.version$ or later, and note
that it is important that all `pekko-*`
+Apache Pekko Projections R2DBC depends on Pekko $pekko.version$ or later, and
note that it is important that all `pekko-*`
dependencies are in the same version, so it is recommended to depend on them
explicitly to avoid problems
with transient dependencies causing an unlucky mix of versions.
@@ -51,6 +51,9 @@ PostgreSQL
YugaByte
: @@snip [YugaByte
Schema](/r2dbc-int-test/ddl-scripts/create_tables_yugabyte.sql)
+MySQL
+: @@snip [MySQL Schema](/r2dbc-int-test/ddl-scripts/create_tables_mysql.sql)
+
## Configuration
By default, `pekko-projection-r2dbc` uses the same connection pool and
`dialect` as `pekko-persistence-r2dbc`, see
@@ -77,7 +80,7 @@ Java
The @ref:[`ShoppingCartHandler` is shown below](#handler).
-It is possible to dynamically scale the number of Projection instances as
described in @extref:[Sharded Daemon Process
documentation](pekko:typed/cluster-sharded-daemon-process.html#dynamic-scaling-of-number-of-workers).
+It is possible to dynamically scale the number of Projection instances as
described in @extref:[Sharded Daemon Process
documentation](pekko:typed/cluster-sharded-daemon-process.html#dynamic-scaling-of-number-of-workers).
There are alternative ways of running the `ProjectionBehavior` as described in
@ref:[Running a Projection](running.md), but note that when using the R2DBC
plugin as `SourceProvider` it is recommended to use `eventsBySlices` and not
`eventsByTag`.
@@ -222,8 +225,8 @@ A good alternative for advanced state management is to
implement the handler as
### Flow handler
-A Pekko Streams `FlowWithContext` can be used instead of a handler for
processing the envelopes,
-which is described in @ref:[Processing with Pekko Streams](flow.md).
+An Apache Pekko Streams `FlowWithContext` can be used instead of a handler for
processing the envelopes,
+which is described in @ref:[Processing with Apache Pekko Streams](flow.md).
### Handler lifecycle
diff --git a/docs/src/main/paradox/release-notes/releases-1.0.md
b/docs/src/main/paradox/release-notes/releases-1.0.md
index d862bcf4..4647da01 100644
--- a/docs/src/main/paradox/release-notes/releases-1.0.md
+++ b/docs/src/main/paradox/release-notes/releases-1.0.md
@@ -8,7 +8,7 @@ a license that is not compatible with Open Source usage.
Apache Pekko has changed the package names, among other changes. Config names
have changed to use `pekko` instead
of `akka` in their names. Users switching from Akka to Pekko should read our
[Migration
Guide](https://pekko.apache.org/docs/pekko/1.0/project/migration-guides.html).
-Generally, we have tried to make it as easy as possible to switch existing
Akka based projects over to using Pekko.
+Generally, we have tried to make it as easy as possible to switch existing
Akka based projects over to using Apache Pekko.
We have gone through the code base and have tried to properly acknowledge all
third party source code in the
Apache Pekko code base. If anyone believes that there are any instances of
third party source code that is not
@@ -23,7 +23,7 @@ We haven't had to fix any significant bugs that were in Akka
Projections 1.2.5.
* pekko-projection-slick does not yet support Scala 3 (Slick does not yet
have a full release that supports Scala 3)
### Dependency Upgrades
-We have tried to limit the changes to third party dependencies that are used
in Pekko Projections 1.0.0. These are some exceptions:
+We have tried to limit the changes to third party dependencies that are used
in Apache Pekko Projections 1.0.0. These are some exceptions:
* jackson 2.14.3
* scalatest 3.2.14. Pekko users who have existing tests based on Akka Testkit
may need to migrate their tests due to the scalatest upgrade. The [scalatest
3.2 release notes](https://www.scalatest.org/release_notes/3.2.0) have a
detailed description of the changes needed.
diff --git a/docs/src/main/paradox/running.md b/docs/src/main/paradox/running.md
index 77d1741a..5a68ddd4 100644
--- a/docs/src/main/paradox/running.md
+++ b/docs/src/main/paradox/running.md
@@ -4,7 +4,7 @@ Once you have decided how you want to build your projection,
the next step is to
## Dependencies
-To distribute the projection over the cluster we recommend the use of
[ShardedDaemonProcess](https://pekko.apache.org/docs/pekko/current/typed/cluster-sharded-daemon-process.html).
Add the following dependency in your project if not yet using Apache Pekko
Cluster Sharding:
+To distribute the projection over the cluster we recommend the use of
@extref:[ShardedDaemonProcess](pekko:typed/cluster-sharded-daemon-process.html).
Add the following dependency in your project if not yet using Apache Pekko
Cluster Sharding:
@@dependency [sbt,Maven,Gradle] {
group=org.apache.pekko
@@ -14,13 +14,13 @@ To distribute the projection over the cluster we recommend
the use of [ShardedDa
Apache Pekko Projections require Pekko $pekko.version$ or later, see
@ref:[Pekko version](overview.md#pekko-version).
-For more information on using Apache Pekko Cluster consult Pekko's reference
documentation on [Apache Pekko
Cluster](https://pekko.apache.org/docs/pekko/current/typed/index-cluster.html)
and [Apache Pekko Cluster
Sharding](https://pekko.apache.org/docs/pekko/current/typed/cluster-sharding.html).
+For more information on using Apache Pekko Cluster consult Pekko's reference
documentation on @extref:[Apache Pekko Cluster](pekko:typed/index-cluster.html)
and @extref:[Apache Pekko Cluster Sharding](pekko:typed/cluster-sharding.html).
## Running with Sharded Daemon Process
The Sharded Daemon Process can be used to distribute `n` instances of a given
Projection across the cluster. Therefore, it's important that each Projection
instance consumes a subset of the stream of envelopes.
-How the subset is created depends on the kind of source we consume. If it's an
Apache Pekko Connectors Kafka source, this is done by Kafka consumer groups.
When consuming from Apache Pekko Persistence Journal, the events must be sliced
by tagging them as demonstrated in the example below.
+How the subset is created depends on the kind of source we consume. If it's an
Apache Pekko Connectors Kafka source, this is done by Kafka consumer groups.
When consuming from Apache Pekko Persistence Journal, the events must be
partitioned by tagging them as demonstrated in the example below, or by the
built-in slices in @ref:[Projections R2DBC](r2dbc.md#slices).
### Tagging Events in EventSourcedBehavior
@@ -41,6 +41,10 @@ Projection instance, which is fine. It's good to start with
more tags than nodes
to more nodes later if needed. As a rule of thumb, the number of tags should
be a factor of ten greater than the
planned maximum number of cluster nodes. It doesn't have to be exact.
+@@@ note
+When using slices with @ref:[Projections R2DBC](r2dbc.md#slices) it is
possible to dynamically change the number of projection instances at runtime.
+@@@
+
We will use those tags to query the journal and create as many Projections
instances, and distribute them in the cluster.
@@@ warning
@@ -48,10 +52,11 @@ When using [Apache Pekko Persistence Cassandra
plugin](https://pekko.apache.org/
not use too many tags for each event. Each tag will result in a copy of the
event in a separate table and
that can impact write performance. Typically, you would use 1 tag per event as
illustrated here. Additional
filtering of events can be done in the Projection handler if it doesn't have
to act on certain events.
-The [JDBC
plugin](https://pekko.apache.org/docs/pekko-persistence-jdbc/current/) doesn't
have this constraint.
+The [JDBC
plugin](https://pekko.apache.org/docs/pekko-persistence-jdbc/current/)
+doesn't have this constraint.
@@@
-See also the [Apache Pekko reference documentation for
tagging](https://pekko.apache.org/docs/pekko/current/typed/persistence.html#tagging).
+See also the @extref:[Apache Pekko reference documentation for
tagging](pekko:typed/persistence.html#tagging).
### Event Sourced Provider per tag
@@ -112,7 +117,7 @@ overwrite each others offset storage with undefined and
unpredictable results.
## Running in Cluster Singleton
If you know that you only need one or a few projection instances an
alternative to @ref:[Sharded Daemon
Process](#running-with-sharded-daemon-process)
-is to use [Apache Pekko Cluster
Singleton](https://pekko.apache.org/docs/pekko/current/typed/cluster-singleton.html)
+is to use @extref:[Apache Pekko Cluster
Singleton](pekko:typed/cluster-singleton.html)
Scala
: @@snip
[CassandraProjectionDocExample.scala](/integration-examples/src/test/scala/docs/cassandra/CassandraProjectionDocExample.scala)
{ #running-with-singleton }
diff --git a/docs/src/main/paradox/slick.md b/docs/src/main/paradox/slick.md
index db9d6c19..420f81d9 100644
--- a/docs/src/main/paradox/slick.md
+++ b/docs/src/main/paradox/slick.md
@@ -123,13 +123,13 @@ than the one that called `process`.
It is important that the `Handler` instance is not shared between several
`Projection` instances,
because then it would be invoked concurrently, which is not how it is intended
to be used. Each `Projection`
-instance should use a new `Handler` instance.
+instance should use a new `Handler` instance.
@@@
### Async handler
-The @apidoc[Handler] can be used with `SlickProjection.atLeastOnceAsync` and
+The @apidoc[Handler] can be used with `SlickProjection.atLeastOnceAsync` and
`SlickProjection.groupedWithinAsync` if the handler is not storing the
projection result in the database.
The handler could @ref:[send to a Kafka topic](kafka.md#sending-to-kafka) or
integrate with something else.
@@ -138,7 +138,7 @@ Same type of handlers can be used with `SlickProjection`
instead of `CassandraPr
### Actor handler
-A good alternative for advanced state management is to implement the handler
as an [actor](https://pekko.apache.org/docs/pekko/current/typed/actors.html),
+A good alternative for advanced state management is to implement the handler
as an @extref:[actor](pekko:typed/actors.html),
which is described in @ref:[Processing with Actor](actor.md).
### Flow handler
@@ -175,20 +175,6 @@ H2
The schema can be created and dropped using the methods
`SlickProjection.createTablesIfNotExists` and
`SlickProjection.dropTablesIfExists`. This is particularly useful when writting
tests. For production enviornments, we recommend creating the schema before
deploying the application.
-@@@ warning { title=Important }
-As of version 1.1.0, the schema for PostgreSQL and H2 databases has changed.
It now defaults to lowercase table and column names.
-If you have a schema in production, we recommend applying an ALTER table
script to change it accordingly.
-
-Alternatively, you can fallback to the uppercase format. You will also need to
set `pekko.projection.slick.offset-store.table` as an uppercase value, as this
setting is now defaulting to lowercase.
-
-```hocon
-pekko.projection.slick.offset-store {
- table = "PEKKO_PROJECTION_OFFSET_STORE"
- use-lowercase-schema = false
-}
-```
-@@@
-
## Offset types
The supported offset types of the `SlickProjection` are:
diff --git a/docs/src/main/paradox/snapshots.md
b/docs/src/main/paradox/snapshots.md
index 0c539692..09517d89 100644
--- a/docs/src/main/paradox/snapshots.md
+++ b/docs/src/main/paradox/snapshots.md
@@ -1,5 +1,5 @@
---
-project.description: Snapshot builds of Pekko Projection are provided via the
Sonatype snapshot repository.
+project.description: Snapshot builds of Apache Pekko Projection are provided
via the Sonatype snapshot repository.
---
# Snapshots
diff --git a/docs/src/main/paradox/testing.md b/docs/src/main/paradox/testing.md
index e4744d3a..a44da107 100644
--- a/docs/src/main/paradox/testing.md
+++ b/docs/src/main/paradox/testing.md
@@ -1,6 +1,6 @@
# Testing
-Apache Pekko Projections provides a TestKit to ease testing. There are two
supported styles of test: running with an assert function and driving it with
an Apache Pekko Streams TestKit `TestSubscriber.Probe`.
+Apache Pekko Projections provides a TestKit to ease testing. There are two
supported styles of test: running with an assert function and driving it with
an Apache Pekko Streams TestKit `TestSink` probe.
## Dependencies
@@ -25,7 +25,7 @@ The table below shows `pekko-projection-testkit`'s direct
dependencies and the s
## Initializing the Projection TestKit
-The Projection TestKit requires an instance of `ActorTestKit`. We recommend
using Pekko's @scala[`ScalaTestWithActorTestKit`]@java[`TestKitJunitResource`]
+The Projection TestKit requires an instance of `ActorTestKit`. We recommend
using Apache Pekko's
@scala[`ScalaTestWithActorTestKit`]@java[`TestKitJunitResource`]
Scala
: @@snip
[TestKitDocExample.scala](/examples/src/test/scala/docs/testkit/TestKitDocExample.scala)
{ #testkit-import #testkit }
@@ -37,7 +37,7 @@ Java
When testing with an assert function the Projection is started and stopped by
the TestKit. While the projection is running, the assert function will be
called until it completes without errors (no exceptions or assertion errors are
thrown).
-In the example below the Projection will update a `CartView`. The test will
run until it observes that the `CartView` for id `abc-def` is available in the
repository.
+In the example below the Projection will update a `CartView`. The test will
run until it observes that the `CartView` for id `abc-def` is available in the
repository.
Scala
: @@snip
[TestKitDocExample.scala](/examples/src/test/scala/docs/testkit/TestKitDocExample.scala)
{ #testkit-import #testkit-run }
@@ -54,13 +54,13 @@ Scala
: @@snip
[TestKitDocExample.scala](/examples/src/test/scala/docs/testkit/TestKitDocExample.scala)
{ #testkit-duration #testkit-run-max-interval }
Java
-: @@snip
[TestKitDocExample.java](/examples/src/test/java/jdocs/testkit/TestKitDocExample.java)
{ #testkit-duration #testkit-run-max-interval }
+: @@snip
[TestKitDocExample.java](/examples/src/test/java/jdocs/testkit/TestKitDocExample.java)
{ #testkit-duration #testkit-run-max-interval }
-## Testing with a TestSubscriber.Probe
+## Testing with a TestSink probe
-The [Apache Pekko Stream
TestKit](https://pekko.apache.org/docs/pekko/current/stream/stream-testkit.html#using-the-testkit)
can be used to drive the pace of envelopes flowing through the Projection.
+The @extref:[Apache Pekko Stream
TestKit](pekko:stream/stream-testkit.html#using-the-testkit) can be used to
drive the pace of envelopes flowing through the Projection.
-The Projection starts as soon as the first element is requested by the
`TestSubscriber.Probe`, new elements will be emitted as requested. The
Projection is stopped once the assert function completes.
+The Projection starts as soon as the first element is requested by the
`TestSink` probe, new elements will be emitted as requested. The Projection is
stopped once the assert function completes.
Scala
: @@snip
[TestKitDocExample.scala](/examples/src/test/scala/docs/testkit/TestKitDocExample.scala)
{ #testkit-sink-probe }
@@ -76,7 +76,7 @@ The @apidoc[TestProjection] allows you to isolate the runtime
of your handler so
Using a `TestProjection` has the added benefit of being fast, since you can
run everything within the JVM that runs your tests.
Alongside the `TestProjection` is the @apidoc[TestSourceProvider] which can be
used to provide test data to the `TestProjection` running the handler.
-Test data can be represented in a Pekko streams
@apidoc[pekko.stream.(javadsl|scaladsl).Source] that is passed to the
`TestSourceProvider` constructor.
+Test data can be represented in an Apache Pekko streams
@apidoc[pekko.stream.(javadsl|scaladsl).Source] that is passed to the
`TestSourceProvider` constructor.
Scala
: @@snip
[TestKitDocExample.scala](/examples/src/test/scala/docs/testkit/TestKitDocExample.scala)
{ #testkit-testprojection }
diff --git a/docs/src/main/paradox/use-cases.md
b/docs/src/main/paradox/use-cases.md
index 6b7f08ba..82325093 100644
--- a/docs/src/main/paradox/use-cases.md
+++ b/docs/src/main/paradox/use-cases.md
@@ -2,7 +2,7 @@
Apache Pekko Projections is intended for the following primary use cases. It
is not limited to these use cases,
because it is designed to be flexible in the way different sources and targets
of the projections can be
-composed.
+composed.
## Command Query Responsibility Segregation (CQRS)
diff --git a/project/Dependencies.scala b/project/Dependencies.scala
index 4dff6d2e..03a1e26a 100644
--- a/project/Dependencies.scala
+++ b/project/Dependencies.scala
@@ -19,8 +19,8 @@ object Dependencies {
val ScalaVersions = Seq(Scala213, Scala3)
val PekkoVersionInDocs = PekkoCoreDependency.default.link
- // change PekkoPersistenceR2dbcVersionInDocs when 2.0.0-M1 is released
- val PekkoPersistenceR2dbcVersionInDocs = "current"
+ val PekkoGrpcVersionInDocs = "2.0"
+ val PekkoPersistenceR2dbcVersionInDocs =
PekkoPersistenceR2DBCDependency.default.link
val ConnectorsVersionInDocs = PekkoConnectorsDependency.default.link
val ConnectorsKafkaVersionInDocs =
PekkoConnectorsKafkaDependency.default.link
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]