@@ -9,7 +9,10 @@ import (
99 "syscall"
1010 "time"
1111
12+ "github.com/rs/zerolog/log"
1213 "github.com/spf13/cobra"
14+ "google.golang.org/grpc/codes"
15+ "google.golang.org/grpc/status"
1316
1417 v1 "github.com/authzed/authzed-go/proto/authzed/api/v1"
1518
@@ -44,20 +47,24 @@ func RegisterWatchRelationshipCmd(parentCmd *cobra.Command) *cobra.Command {
4447
4548var watchCmd = & cobra.Command {
4649 Use : "watch [object_types, ...] [start_cursor]" ,
47- Short : "Watches the stream of relationship updates from the server" ,
50+ Short : "Watches the stream of relationship updates and schema updates from the server" ,
4851 Args : ValidationWrapper (cobra .RangeArgs (0 , 2 )),
4952 RunE : watchCmdFunc ,
5053 Deprecated : "please use `zed relationships watch` instead" ,
5154}
5255
5356var watchRelationshipsCmd = & cobra.Command {
5457 Use : "watch [object_types, ...] [start_cursor]" ,
55- Short : "Watches the stream of relationship updates from the server" ,
58+ Short : "Watches the stream of relationship updates and schema updates from the server" ,
5659 Args : ValidationWrapper (cobra .RangeArgs (0 , 2 )),
5760 RunE : watchCmdFunc ,
5861}
5962
6063func watchCmdFunc (cmd * cobra.Command , _ []string ) error {
64+ return watchCmdFuncImpl (cmd , processResponse )
65+ }
66+
67+ func watchCmdFuncImpl (cmd * cobra.Command , processResponse func (resp * v1.WatchResponse )) error {
6168 console .Printf ("starting watch stream over types %v and revision %v\n " , watchObjectTypes , watchRevision )
6269
6370 cli , err := client .NewClient (cmd )
@@ -74,20 +81,25 @@ func watchCmdFunc(cmd *cobra.Command, _ []string) error {
7481 relFilters = append (relFilters , relFilter )
7582 }
7683
84+ ctx , cancel := context .WithCancel (cmd .Context ())
85+ defer cancel ()
86+
87+ signalctx , interruptCancel := signal .NotifyContext (ctx , os .Interrupt , syscall .SIGTERM , syscall .SIGINT )
88+ defer interruptCancel ()
89+
7790 req := & v1.WatchRequest {
7891 OptionalObjectTypes : watchObjectTypes ,
7992 OptionalRelationshipFilters : relFilters ,
93+ OptionalUpdateKinds : []v1.WatchKind {
94+ v1 .WatchKind_WATCH_KIND_INCLUDE_CHECKPOINTS ,
95+ v1 .WatchKind_WATCH_KIND_INCLUDE_SCHEMA_UPDATES ,
96+ },
8097 }
98+
8199 if watchRevision != "" {
82100 req .OptionalStartCursor = & v1.ZedToken {Token : watchRevision }
83101 }
84102
85- ctx , cancel := context .WithCancel (cmd .Context ())
86- defer cancel ()
87-
88- signalctx , interruptCancel := signal .NotifyContext (ctx , os .Interrupt , syscall .SIGTERM , syscall .SIGINT )
89- defer interruptCancel ()
90-
91103 watchStream , err := cli .Watch (ctx , req )
92104 if err != nil {
93105 return err
@@ -104,40 +116,74 @@ func watchCmdFunc(cmd *cobra.Command, _ []string) error {
104116 default :
105117 resp , err := watchStream .Recv ()
106118 if err != nil {
107- return err
108- }
119+ err , ok := isRetryable (err )
120+ if ! ok {
121+ return err
122+ }
109123
110- for _ , update := range resp .Updates {
111- if watchTimestamps {
112- console .Printf ("%v: " , time .Now ())
124+ log .Trace ().Err (err ).Msg ("will retry from the last known revision " + watchRevision )
125+ req .OptionalStartCursor = & v1.ZedToken {Token : watchRevision }
126+ watchStream , err = cli .Watch (ctx , req )
127+ if err != nil {
128+ return err
113129 }
130+ continue
131+ }
114132
115- switch update .Operation {
116- case v1 .RelationshipUpdate_OPERATION_CREATE :
117- console .Printf ("CREATED " )
133+ processResponse (resp )
134+ }
135+ }
136+ }
118137
119- case v1 .RelationshipUpdate_OPERATION_DELETE :
120- console .Printf ("DELETED " )
138+ func isRetryable (err error ) (error , bool ) {
139+ statusErr , ok := status .FromError (err )
140+ if ! ok || (statusErr .Code () != codes .Unavailable ) {
141+ return err , false
142+ }
143+ return nil , true
144+ }
121145
122- case v1 .RelationshipUpdate_OPERATION_TOUCH :
123- console .Printf ("TOUCHED " )
124- }
146+ func processResponse (resp * v1.WatchResponse ) {
147+ if resp .ChangesThrough != nil {
148+ watchRevision = resp .ChangesThrough .Token
149+ }
125150
126- subjectRelation := ""
127- if update .Relationship .Subject .OptionalRelation != "" {
128- subjectRelation = " " + update .Relationship .Subject .OptionalRelation
129- }
151+ if resp .SchemaUpdated {
152+ if watchTimestamps {
153+ console .Printf ("%v: " , time .Now ())
154+ }
155+ console .Println ("SCHEMA UPDATED" )
156+ }
130157
131- console .Printf ("%s:%s %s %s:%s%s\n " ,
132- update .Relationship .Resource .ObjectType ,
133- update .Relationship .Resource .ObjectId ,
134- update .Relationship .Relation ,
135- update .Relationship .Subject .Object .ObjectType ,
136- update .Relationship .Subject .Object .ObjectId ,
137- subjectRelation ,
138- )
139- }
158+ for _ , update := range resp .Updates {
159+ if watchTimestamps {
160+ console .Printf ("%v: " , time .Now ())
140161 }
162+
163+ switch update .Operation {
164+ case v1 .RelationshipUpdate_OPERATION_CREATE :
165+ console .Printf ("CREATED " )
166+
167+ case v1 .RelationshipUpdate_OPERATION_DELETE :
168+ console .Printf ("DELETED " )
169+
170+ case v1 .RelationshipUpdate_OPERATION_TOUCH :
171+ console .Printf ("TOUCHED " )
172+ }
173+
174+ subjectRelation := ""
175+ if update .Relationship .Subject .OptionalRelation != "" {
176+ subjectRelation = " " + update .Relationship .Subject .OptionalRelation
177+ }
178+
179+ console .Printf ("%s:%s %s %s:%s%s\n " ,
180+ update .Relationship .Resource .ObjectType ,
181+ update .Relationship .Resource .ObjectId ,
182+ update .Relationship .Relation ,
183+ update .Relationship .Subject .Object .ObjectType ,
184+ update .Relationship .Subject .Object .ObjectId ,
185+ subjectRelation ,
186+ )
141187 }
142188}
143189
0 commit comments