Skip to content

Commit e0dc6c4

Browse files
authored
update watch docs (#382)
1 parent 444af85 commit e0dc6c4

File tree

1 file changed

+106
-21
lines changed

1 file changed

+106
-21
lines changed

pages/spicedb/concepts/watch.mdx

Lines changed: 106 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -13,28 +13,50 @@ Watch events are generated when relationships are created, touched, or deleted t
1313
[DeleteRelationships]: https://buf.build/authzed/api/docs/main:authzed.api.v1#authzed.api.v1.PermissionsService.DeleteRelationships
1414
[ImportBulkRelationships]: https://buf.build/authzed/api/docs/main:authzed.api.v1#authzed.api.v1.PermissionsService.ImportBulkRelationships
1515

16-
## Subscribing to Watch
16+
## Calling Watch
1717

18-
To subscribe to receive watch changes, the `Watch` API call is made:
18+
To receive watch changes, call the `Watch` API.
19+
20+
This is a streaming API that will continually return all updates to relationships from the time at which the API call was made.
1921

2022
```py
23+
from authzed.api.v1 import (
24+
Client, WatchRequest
25+
)
26+
from grpcutil import bearer_token_credentials
27+
28+
client = Client(
29+
"localhost:50051",
30+
bearer_token_credentials("your-token-here"),
31+
)
32+
2133
watcher = client.Watch(WatchRequest{})
2234
for resp in watcher:
23-
... process the update ...
35+
# process the update
2436
```
2537

26-
This will start returning all updates to relationships from the time at which the API call was made.
27-
2838
### Receiving historical updates
2939

3040
Historical updates (i.e. relationship changes in the past) can be retrieved by specifying a [ZedToken] in the `WatchRequest`:
3141

3242
[ZedToken]: consistency#zedtokens
3343

3444
```py
35-
watcher = client.Watch(WatchRequest{
36-
OptionalStartCursor: myZedToken
37-
})
45+
from authzed.api.v1 import (
46+
Client, WatchRequest
47+
)
48+
from grpcutil import bearer_token_credentials
49+
50+
client = Client(
51+
"localhost:50051",
52+
bearer_token_credentials("your-token-here"),
53+
)
54+
55+
watcher = client.Watch(WatchRequest(
56+
optional_start_cursor=last_zed_token
57+
))
58+
for resp in watcher:
59+
# process the update
3860
```
3961

4062
<Callout type="info">
@@ -45,20 +67,64 @@ watcher = client.Watch(WatchRequest{
4567

4668
### Ensuring continuous processing
4769

70+
Because Watch is a streaming API, your code should handle disconnections gracefully.
71+
4872
To ensure continuous processing, the calling client _should_ execute the `Watch` call in a loop, sending in the last received [ZedToken] from `ChangesThrough` if the call disconnects:
4973

5074
```py
75+
from authzed.api.v1 import (
76+
Client, WatchRequest
77+
)
78+
from grpcutil import bearer_token_credentials
79+
80+
client = Client(
81+
"localhost:50051",
82+
bearer_token_credentials("your-token-here"),
83+
)
84+
85+
last_zed_token = None
86+
while not_canceled:
87+
try:
88+
watcher = client.Watch(WatchRequest(
89+
optional_start_cursor=last_zed_token
90+
))
91+
for resp in watcher:
92+
# process the update
93+
last_zed_token = resp.changes_through
94+
except Exception:
95+
# log exception
96+
continue
97+
```
98+
99+
If your datastore supports checkpoints, you can also request them.
100+
101+
This will help keep the stream alive during periods of inactivity, which is helpful if your SpiceDB instance sits behind a proxy that terminates idle connections.
102+
103+
```py
104+
from authzed.api.v1 import (
105+
Client,
106+
WatchRequest,
107+
)
108+
from authzed.api.v1.watch_service_pb2 import WATCH_KIND_INCLUDE_CHECKPOINTS
109+
from grpcutil import bearer_token_credentials
110+
111+
client = Client(
112+
"localhost:50051",
113+
bearer_token_credentials("your-token-here"),
114+
)
115+
116+
last_zed_token = None
51117
while not_canceled:
52-
last_zed_token = None
53118
try:
54-
watcher = client.Watch(WatchRequest{
55-
OptionalStartCursor: last_zed_token
56-
})
119+
watcher = client.Watch(WatchRequest(
120+
optional_start_cursor=last_zed_token,
121+
optional_update_kinds=[WATCH_KIND_INCLUDE_CHECKPOINTS]
122+
))
57123
for resp in watcher:
58-
... process the update ...
59-
last_zed_token = resp.ChangesThrough
124+
# process the update
125+
last_zed_token = resp.changes_through
60126
except Exception:
61-
... log exception ...
127+
# log exception
62128
continue
63129
```
64130

@@ -69,13 +135,32 @@ SpiceDB's [WriteRelationships] and [DeleteRelationships] APIs support an optiona
69135
When `optional_transaction_metadata` is specified on the [WriteRelationships] or [DeleteRelationships] request, it will be stored and returned alongside the relationships in the Watch API:
70136

71137
```py
72-
client.WriteRelationships(WriteRelationshipsRequest{
73-
Updates: [
74-
{ Relationship: "document:somedoc#viewer@user:tom" }
138+
from authzed.api.v1 import (
139+
Client, WatchRequest
140+
)
141+
from grpcutil import bearer_token_credentials
142+
143+
client = Client(
144+
"localhost:50051",
145+
bearer_token_credentials("your-token-here"),
146+
)
147+
client.WriteRelationships(WriteRelationshipsRequest(
148+
updates=[
149+
RelationshipUpdate(
150+
operation=RelationshipUpdate.Operation.OPERATION_CREATE,
151+
relationship=Relationship(
152+
resource=ObjectReference(object_type="document", object_id="somedoc"),
153+
relation="viewer",
154+
subject=SubjectReference(
155+
object=ObjectReference(
156+
object_type="user",
157+
object_id="tom",
158+
)
159+
),
160+
),
161+
),
75162
],
76-
OptionalTransactionMetadata: {
77-
"request_id": "12345"
78-
}
163+
optional_transaction_metadata=Struct({"request_id": "12345"}),
79164
})
80165

81166
...

0 commit comments

Comments
 (0)