kurrentdbclient 1.2.2__tar.gz → 1.2.3__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/PKG-INFO +131 -114
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/README.md +128 -111
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/__init__.py +1 -1
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/common.py +8 -5
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/exceptions.py +3 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/instrumentation/opentelemetry/grpc.py +3 -3
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/instrumentation/opentelemetry/spanners.py +2 -2
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/persistent.py +94 -52
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/streams.py +85 -44
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/pyproject.toml +3 -3
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/LICENSE +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/.DS_Store +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/asyncio_client.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/client.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/connection.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/connection_spec.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/events.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/gossip.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/instrumentation/__init__.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/instrumentation/opentelemetry/__init__.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/instrumentation/opentelemetry/attributes.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/instrumentation/opentelemetry/package.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/instrumentation/opentelemetry/utils.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/instrumentation/opentelemetry/version.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/projections.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/google/rpc/code_pb2.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/google/rpc/code_pb2.pyi +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/google/rpc/code_pb2_grpc.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/kurrent/rpc/errors_pb2.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/kurrent/rpc/errors_pb2.pyi +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/kurrent/rpc/errors_pb2_grpc.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/kurrent/rpc/rpc_pb2.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/kurrent/rpc/rpc_pb2.pyi +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/kurrent/rpc/rpc_pb2_grpc.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/v1/cluster_pb2.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/v1/cluster_pb2.pyi +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/v1/cluster_pb2_grpc.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/v1/gossip_pb2.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/v1/gossip_pb2.pyi +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/v1/gossip_pb2_grpc.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/v1/persistent_pb2.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/v1/persistent_pb2.pyi +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/v1/persistent_pb2_grpc.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/v1/projections_pb2.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/v1/projections_pb2.pyi +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/v1/projections_pb2_grpc.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/v1/shared_pb2.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/v1/shared_pb2.pyi +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/v1/shared_pb2_grpc.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/v1/status_pb2.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/v1/status_pb2.pyi +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/v1/status_pb2_grpc.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/v1/streams_pb2.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/v1/streams_pb2.pyi +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/v1/streams_pb2_grpc.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/v2/streams/errors_pb2.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/v2/streams/errors_pb2.pyi +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/v2/streams/errors_pb2_grpc.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/v2/streams/streams_pb2.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/v2/streams/streams_pb2.pyi +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/protos/v2/streams/streams_pb2_grpc.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/py.typed +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/unpack_error_status.py +0 -0
- {kurrentdbclient-1.2.2 → kurrentdbclient-1.2.3}/kurrentdbclient/v2streams.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: kurrentdbclient
|
|
3
|
-
Version: 1.2.
|
|
3
|
+
Version: 1.2.3
|
|
4
4
|
Summary: Python gRPC Client for KurrentDB
|
|
5
5
|
License: BSD-3-Clause
|
|
6
6
|
License-File: LICENSE
|
|
@@ -21,8 +21,8 @@ Requires-Dist: googleapis-common-protos
|
|
|
21
21
|
Requires-Dist: grpcio-status
|
|
22
22
|
Requires-Dist: grpcio[protobuf] (>=1.75.1,<2.0)
|
|
23
23
|
Requires-Dist: opentelemetry-api (>=1.28.0,<2.0) ; extra == "opentelemetry"
|
|
24
|
-
Requires-Dist: opentelemetry-instrumentation (>=0.
|
|
25
|
-
Requires-Dist: opentelemetry-semantic-conventions (>=0.
|
|
24
|
+
Requires-Dist: opentelemetry-instrumentation (>=0.62b1) ; extra == "opentelemetry"
|
|
25
|
+
Requires-Dist: opentelemetry-semantic-conventions (>=0.62b1) ; extra == "opentelemetry"
|
|
26
26
|
Requires-Dist: typing_extensions
|
|
27
27
|
Project-URL: Homepage, https://github.com/pyeventsourcing/kurrentdbclient
|
|
28
28
|
Project-URL: Repository, https://github.com/pyeventsourcing/kurrentdbclient
|
|
@@ -52,9 +52,10 @@ with the KurrentDB team, and are officially supported by Kurrent Inc.
|
|
|
52
52
|
Although not all aspects of the KurrentDB gRPC API are implemented, most
|
|
53
53
|
features are presented in an easy-to-use interface.
|
|
54
54
|
|
|
55
|
-
These clients have been tested to work with KurrentDB
|
|
56
|
-
|
|
57
|
-
cluster modes, across Python versions 3.10, 3.11, 3.12,
|
|
55
|
+
These clients have been tested to work with KurrentDB versions 25.0, 25.1, 26.0,
|
|
56
|
+
and 26.1, and EventStoreDB versions 23.10 and 24.10, with and without SSL/TLS,
|
|
57
|
+
in both single-server and cluster modes, across Python versions 3.10, 3.11, 3.12,
|
|
58
|
+
3.13, and 3.14.
|
|
58
59
|
|
|
59
60
|
The test suite has 100% line and branch coverage. The code has typing annotations
|
|
60
61
|
checked strictly with mypy. The code is formatted with black and isort, and checked
|
|
@@ -1715,10 +1716,10 @@ so far, in the order they were recorded. We can see the three events of `stream_
|
|
|
1715
1716
|
|
|
1716
1717
|
```python
|
|
1717
1718
|
# Read all events (creates a streaming gRPC call).
|
|
1718
|
-
|
|
1719
|
+
with client.read_all() as read_response:
|
|
1720
|
+
# Convert the iterator into a sequence of recorded events.
|
|
1721
|
+
events = tuple(read_response)
|
|
1719
1722
|
|
|
1720
|
-
# Convert the iterator into a sequence of recorded events.
|
|
1721
|
-
events = tuple(read_response)
|
|
1722
1723
|
assert len(events) > 3 # more than three
|
|
1723
1724
|
|
|
1724
1725
|
# Convert the sequence of recorded events into a set of event IDs.
|
|
@@ -1737,17 +1738,14 @@ receive, `event2` is the second, and `event3` is the third.
|
|
|
1737
1738
|
|
|
1738
1739
|
```python
|
|
1739
1740
|
# Read all events forwards from a commit position.
|
|
1740
|
-
|
|
1741
|
+
with client.read_all(
|
|
1741
1742
|
commit_position=commit_position1
|
|
1742
|
-
)
|
|
1743
|
-
|
|
1744
|
-
# Step through the "read response" iterator.
|
|
1745
|
-
assert next(read_response) == event1
|
|
1746
|
-
assert next(read_response) == event2
|
|
1747
|
-
assert next(read_response) == event3
|
|
1743
|
+
) as read_response:
|
|
1748
1744
|
|
|
1749
|
-
#
|
|
1750
|
-
read_response
|
|
1745
|
+
# Step through the "read response" iterator.
|
|
1746
|
+
assert next(read_response) == event1
|
|
1747
|
+
assert next(read_response) == event2
|
|
1748
|
+
assert next(read_response) == event3
|
|
1751
1749
|
```
|
|
1752
1750
|
|
|
1753
1751
|
The example below shows how to read all events recorded in the database in reverse
|
|
@@ -1757,31 +1755,27 @@ and the snapshot.
|
|
|
1757
1755
|
|
|
1758
1756
|
```python
|
|
1759
1757
|
# Read all events backwards from the end.
|
|
1760
|
-
|
|
1758
|
+
with client.read_all(
|
|
1761
1759
|
backwards=True
|
|
1762
|
-
)
|
|
1760
|
+
) as read_response:
|
|
1763
1761
|
|
|
1764
|
-
# Step through the "read response" iterator.
|
|
1765
|
-
assert next(read_response).type == "DogLearnedTrick"
|
|
1766
|
-
assert next(read_response).type == "Snapshot"
|
|
1767
|
-
assert next(read_response).type == "DogLearnedTrick"
|
|
1768
|
-
assert next(read_response).type == "DogLearnedTrick"
|
|
1769
|
-
assert next(read_response).type == "DogRegistered"
|
|
1770
|
-
|
|
1771
|
-
# Stop the iterator.
|
|
1772
|
-
read_response.stop()
|
|
1762
|
+
# Step through the "read response" iterator.
|
|
1763
|
+
assert next(read_response).type == "DogLearnedTrick"
|
|
1764
|
+
assert next(read_response).type == "Snapshot"
|
|
1765
|
+
assert next(read_response).type == "DogLearnedTrick"
|
|
1766
|
+
assert next(read_response).type == "DogLearnedTrick"
|
|
1767
|
+
assert next(read_response).type == "DogRegistered"
|
|
1773
1768
|
```
|
|
1774
1769
|
|
|
1775
1770
|
The example below shows how to read a limited number of events
|
|
1776
1771
|
forwards from a specific commit position.
|
|
1777
1772
|
|
|
1778
1773
|
```python
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
)
|
|
1784
|
-
)
|
|
1774
|
+
with client.read_all(
|
|
1775
|
+
commit_position=commit_position1,
|
|
1776
|
+
limit=1,
|
|
1777
|
+
) as read_response:
|
|
1778
|
+
events = tuple(read_response)
|
|
1785
1779
|
|
|
1786
1780
|
assert len(events) == 1
|
|
1787
1781
|
assert events[0] == event1
|
|
@@ -1792,12 +1786,11 @@ in the database backwards from the end. In this case, the limit is 1, and
|
|
|
1792
1786
|
so we receive the last recorded event.
|
|
1793
1787
|
|
|
1794
1788
|
```python
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
)
|
|
1800
|
-
)
|
|
1789
|
+
with client.read_all(
|
|
1790
|
+
backwards=True,
|
|
1791
|
+
limit=1,
|
|
1792
|
+
) as read_response:
|
|
1793
|
+
events = tuple(read_response)
|
|
1801
1794
|
|
|
1802
1795
|
assert len(events) == 1
|
|
1803
1796
|
|
|
@@ -2096,16 +2089,17 @@ from the first recorded event in the database.
|
|
|
2096
2089
|
|
|
2097
2090
|
```python
|
|
2098
2091
|
# Subscribe from the first recorded event in the database.
|
|
2099
|
-
|
|
2092
|
+
with client.subscribe_to_all() as catchup_subscription:
|
|
2093
|
+
...
|
|
2100
2094
|
```
|
|
2101
2095
|
|
|
2102
|
-
The example below shows that catch-up subscriptions
|
|
2103
|
-
|
|
2104
|
-
|
|
2096
|
+
The example below shows that catch-up subscriptions block when the
|
|
2097
|
+
last recorded event is received, and then continue when subsequent
|
|
2098
|
+
events are recorded.
|
|
2105
2099
|
|
|
2106
2100
|
```python
|
|
2107
|
-
|
|
2108
|
-
|
|
2101
|
+
import time
|
|
2102
|
+
import threading
|
|
2109
2103
|
|
|
2110
2104
|
|
|
2111
2105
|
# Append a new event to a new stream.
|
|
@@ -2119,30 +2113,53 @@ client.append_to_stream(
|
|
|
2119
2113
|
)
|
|
2120
2114
|
|
|
2121
2115
|
|
|
2122
|
-
# Receive events from
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2116
|
+
# Receive events from a catch-up subscription in a different thread.
|
|
2117
|
+
class SubscribeToAll(threading.Thread):
|
|
2118
|
+
def __init__(self, client, **subscription_kwargs):
|
|
2119
|
+
super().__init__()
|
|
2120
|
+
self._client = client
|
|
2121
|
+
self._is_running = threading.Event()
|
|
2122
|
+
self._subscription_kwargs = subscription_kwargs
|
|
2123
|
+
self._subscription = None
|
|
2124
|
+
self._seen_event_ids = set()
|
|
2125
|
+
self._last_commit_position = None
|
|
2126
|
+
self.start()
|
|
2128
2127
|
|
|
2128
|
+
def run(self):
|
|
2129
|
+
with self._client.subscribe_to_all(
|
|
2130
|
+
**self._subscription_kwargs
|
|
2131
|
+
) as subscription:
|
|
2132
|
+
self._subscription = subscription
|
|
2133
|
+
self._is_running.set()
|
|
2134
|
+
for event in subscription:
|
|
2135
|
+
self._seen_event_ids.add(event.id)
|
|
2136
|
+
self._last_commit_position = event.commit_position
|
|
2129
2137
|
|
|
2130
|
-
def
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2138
|
+
def stop(self):
|
|
2139
|
+
if not self._is_running.wait(timeout=5):
|
|
2140
|
+
raise TimeoutError("Subscription thread didn't start")
|
|
2141
|
+
self._subscription.stop()
|
|
2142
|
+
self.join()
|
|
2143
|
+
self._subscription = None
|
|
2144
|
+
|
|
2145
|
+
def wait_for_event(self, event):
|
|
2146
|
+
for _ in range(100):
|
|
2147
|
+
if event.id in self._seen_event_ids:
|
|
2134
2148
|
return
|
|
2149
|
+
else:
|
|
2150
|
+
time.sleep(0.1)
|
|
2135
2151
|
else:
|
|
2136
|
-
|
|
2137
|
-
|
|
2138
|
-
|
|
2152
|
+
raise AssertionError("Event wasn't received")
|
|
2153
|
+
|
|
2154
|
+
@property
|
|
2155
|
+
def last_commit_position(self):
|
|
2156
|
+
return self._last_commit_position
|
|
2139
2157
|
|
|
2140
2158
|
|
|
2141
|
-
|
|
2142
|
-
thread.start()
|
|
2159
|
+
subscription_to_all = SubscribeToAll(client=client)
|
|
2143
2160
|
|
|
2144
2161
|
# Wait to receive event4.
|
|
2145
|
-
wait_for_event(event4)
|
|
2162
|
+
subscription_to_all.wait_for_event(event4)
|
|
2146
2163
|
|
|
2147
2164
|
# Append another event whilst the subscription is running.
|
|
2148
2165
|
event5 = NewEvent(type='OrderUpdated', data=b'{}')
|
|
@@ -2152,17 +2169,16 @@ client.append_to_stream(
|
|
|
2152
2169
|
events=[event5],
|
|
2153
2170
|
)
|
|
2154
2171
|
|
|
2155
|
-
# Wait
|
|
2156
|
-
wait_for_event(event5)
|
|
2172
|
+
# Wait to receive event5.
|
|
2173
|
+
subscription_to_all.wait_for_event(event5)
|
|
2157
2174
|
|
|
2158
|
-
# Stop the subscription.
|
|
2159
|
-
|
|
2160
|
-
thread.join()
|
|
2175
|
+
# Stop the subscription thread.
|
|
2176
|
+
subscription_to_all.stop()
|
|
2161
2177
|
```
|
|
2162
2178
|
|
|
2163
2179
|
The example below shows how to subscribe to events recorded after a
|
|
2164
2180
|
particular commit position, in this case from the commit position of
|
|
2165
|
-
the last recorded event that was received above.
|
|
2181
|
+
the last recorded event that was received above. Another event is
|
|
2166
2182
|
recorded before the subscription is restarted. And three more events are
|
|
2167
2183
|
recorded whilst the subscription is running. These four events are
|
|
2168
2184
|
received in the order they were recorded.
|
|
@@ -2180,15 +2196,13 @@ client.append_to_stream(
|
|
|
2180
2196
|
|
|
2181
2197
|
# Restart subscribing to all events after the
|
|
2182
2198
|
# commit position of the last received event.
|
|
2183
|
-
|
|
2184
|
-
|
|
2199
|
+
subscription_to_all = SubscribeToAll(
|
|
2200
|
+
client=client,
|
|
2201
|
+
commit_position=subscription_to_all.last_commit_position
|
|
2185
2202
|
)
|
|
2186
2203
|
|
|
2187
|
-
thread = Thread(target=receive_events, daemon=True)
|
|
2188
|
-
thread.start()
|
|
2189
|
-
|
|
2190
2204
|
# Wait for event6.
|
|
2191
|
-
wait_for_event(event6)
|
|
2205
|
+
subscription_to_all.wait_for_event(event6)
|
|
2192
2206
|
|
|
2193
2207
|
# Append three more events to a new stream.
|
|
2194
2208
|
stream_name3 = str(uuid.uuid4())
|
|
@@ -2203,13 +2217,12 @@ client.append_to_stream(
|
|
|
2203
2217
|
)
|
|
2204
2218
|
|
|
2205
2219
|
# Wait for events 7, 8 and 9.
|
|
2206
|
-
wait_for_event(event7)
|
|
2207
|
-
wait_for_event(event8)
|
|
2208
|
-
wait_for_event(event9)
|
|
2220
|
+
subscription_to_all.wait_for_event(event7)
|
|
2221
|
+
subscription_to_all.wait_for_event(event8)
|
|
2222
|
+
subscription_to_all.wait_for_event(event9)
|
|
2209
2223
|
|
|
2210
|
-
# Stop the subscription.
|
|
2211
|
-
|
|
2212
|
-
thread.join()
|
|
2224
|
+
# Stop the subscription thread.
|
|
2225
|
+
subscription_to_all.stop()
|
|
2213
2226
|
```
|
|
2214
2227
|
|
|
2215
2228
|
The catch-up subscription call is ended as soon as the subscription object's
|
|
@@ -2263,7 +2276,10 @@ the first recorded event in a stream.
|
|
|
2263
2276
|
|
|
2264
2277
|
```python
|
|
2265
2278
|
# Subscribe from the start of 'stream2'.
|
|
2266
|
-
|
|
2279
|
+
with client.subscribe_to_stream(
|
|
2280
|
+
stream_name=stream_name2
|
|
2281
|
+
) as subscription:
|
|
2282
|
+
...
|
|
2267
2283
|
```
|
|
2268
2284
|
|
|
2269
2285
|
The example below shows how to start a catch-up subscription from
|
|
@@ -2271,10 +2287,11 @@ a particular stream position.
|
|
|
2271
2287
|
|
|
2272
2288
|
```python
|
|
2273
2289
|
# Subscribe to stream2, from the second recorded event.
|
|
2274
|
-
|
|
2290
|
+
with client.subscribe_to_stream(
|
|
2275
2291
|
stream_name=stream_name2,
|
|
2276
2292
|
stream_position=1,
|
|
2277
|
-
)
|
|
2293
|
+
) as subscription:
|
|
2294
|
+
...
|
|
2278
2295
|
```
|
|
2279
2296
|
|
|
2280
2297
|
### Subscribe using secondary index<a id="subscribe-to-index"></a>
|
|
@@ -2528,7 +2545,10 @@ giving `RecordedEvent` objects. It also has `ack()`, `nack()` and `stop()`
|
|
|
2528
2545
|
methods.
|
|
2529
2546
|
|
|
2530
2547
|
```python
|
|
2531
|
-
|
|
2548
|
+
with client.read_subscription_to_all(
|
|
2549
|
+
group_name=group_name1
|
|
2550
|
+
) as subscription:
|
|
2551
|
+
...
|
|
2532
2552
|
```
|
|
2533
2553
|
|
|
2534
2554
|
The `ack()` method should be used by a consumer to "acknowledge" to the server that
|
|
@@ -2550,15 +2570,18 @@ examples below.
|
|
|
2550
2570
|
```python
|
|
2551
2571
|
received_events = []
|
|
2552
2572
|
|
|
2553
|
-
|
|
2554
|
-
|
|
2573
|
+
with client.read_subscription_to_all(
|
|
2574
|
+
group_name=group_name1
|
|
2575
|
+
) as subscription:
|
|
2576
|
+
for event in subscription:
|
|
2577
|
+
received_events.append(event)
|
|
2555
2578
|
|
|
2556
|
-
|
|
2557
|
-
|
|
2579
|
+
# Acknowledge the received event.
|
|
2580
|
+
subscription.ack(event)
|
|
2558
2581
|
|
|
2559
|
-
|
|
2560
|
-
|
|
2561
|
-
|
|
2582
|
+
# Stop when 'event9' has been received.
|
|
2583
|
+
if event == event9:
|
|
2584
|
+
subscription.stop()
|
|
2562
2585
|
```
|
|
2563
2586
|
|
|
2564
2587
|
The `nack()` should be used by a consumer to "negatively acknowledge" to the server that
|
|
@@ -2610,9 +2633,6 @@ class ExampleConsumer:
|
|
|
2610
2633
|
self.subscription.ack(event)
|
|
2611
2634
|
self.after_ack(event)
|
|
2612
2635
|
|
|
2613
|
-
def stop(self):
|
|
2614
|
-
self.subscription.stop()
|
|
2615
|
-
|
|
2616
2636
|
def policy(self, event):
|
|
2617
2637
|
# Raise an exception when we see "event5".
|
|
2618
2638
|
if event == event5:
|
|
@@ -2630,17 +2650,17 @@ class ExampleConsumer:
|
|
|
2630
2650
|
# Stop the consumer, so we can continue with the examples.
|
|
2631
2651
|
self.stop()
|
|
2632
2652
|
|
|
2653
|
+
def stop(self):
|
|
2654
|
+
self.subscription.stop()
|
|
2655
|
+
|
|
2633
2656
|
|
|
2634
2657
|
# Create subscription.
|
|
2635
2658
|
group_name = f"group-{uuid.uuid4()}"
|
|
2636
2659
|
client.create_subscription_to_all(group_name, commit_position=commit_position1)
|
|
2637
2660
|
|
|
2638
|
-
# Read subscription.
|
|
2639
|
-
subscription = client.read_subscription_to_all(group_name)
|
|
2640
|
-
|
|
2641
2661
|
# Construct consumer.
|
|
2642
2662
|
consumer = ExampleConsumer(
|
|
2643
|
-
subscription=
|
|
2663
|
+
subscription=client.read_subscription_to_all(group_name),
|
|
2644
2664
|
max_retry_count=5,
|
|
2645
2665
|
final_action="park",
|
|
2646
2666
|
)
|
|
@@ -2819,28 +2839,25 @@ This method returns a `PersistentSubscription` object, which is an iterator
|
|
|
2819
2839
|
giving `RecordedEvent` objects, that also has `ack()`, `nack()` and `stop()`
|
|
2820
2840
|
methods.
|
|
2821
2841
|
|
|
2822
|
-
```python
|
|
2823
|
-
subscription = client.read_subscription_to_stream(
|
|
2824
|
-
group_name=group_name2,
|
|
2825
|
-
stream_name=stream_name2,
|
|
2826
|
-
)
|
|
2827
|
-
```
|
|
2828
|
-
|
|
2829
2842
|
The example below iterates over the subscription object, and calls `ack()`.
|
|
2830
2843
|
The subscription's `stop()` method is called when we have received `event6`,
|
|
2831
2844
|
stopping the iteration, so that we can continue with the examples below.
|
|
2832
2845
|
|
|
2833
2846
|
```python
|
|
2834
2847
|
events = []
|
|
2835
|
-
|
|
2836
|
-
|
|
2848
|
+
with client.read_subscription_to_stream(
|
|
2849
|
+
group_name=group_name2,
|
|
2850
|
+
stream_name=stream_name2,
|
|
2851
|
+
) as subscription:
|
|
2852
|
+
for event in subscription:
|
|
2853
|
+
events.append(event)
|
|
2837
2854
|
|
|
2838
|
-
|
|
2839
|
-
|
|
2855
|
+
# Acknowledge the received event.
|
|
2856
|
+
subscription.ack(event)
|
|
2840
2857
|
|
|
2841
|
-
|
|
2842
|
-
|
|
2843
|
-
|
|
2858
|
+
# Stop when 'event6' has been received.
|
|
2859
|
+
if event == event6:
|
|
2860
|
+
break
|
|
2844
2861
|
```
|
|
2845
2862
|
|
|
2846
2863
|
We can check we received all the events that were appended to `stream_name2`
|
|
@@ -3192,7 +3209,7 @@ to process all the recorded events, the projection "state" is obtained.
|
|
|
3192
3209
|
We can see that the projection has processed three events.
|
|
3193
3210
|
|
|
3194
3211
|
```python
|
|
3195
|
-
sleep(1) # allow time for projection to process recorded events
|
|
3212
|
+
time.sleep(1) # allow time for projection to process recorded events
|
|
3196
3213
|
|
|
3197
3214
|
projection_state = client.get_projection_state(projection_name)
|
|
3198
3215
|
|