aboutsummaryrefslogtreecommitdiff
path: root/google/watcher/v1/watch.proto
blob: 6444398278201ef41e9a664f2e3d80026e54d175 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

syntax = "proto3";

package google.watcher.v1;

import "google/api/annotations.proto";
import "google/protobuf/any.proto";
import "google/protobuf/empty.proto";

option go_package = "google.golang.org/genproto/googleapis/watcher/v1;watcher";
option java_multiple_files = true;
option java_outer_classname = "WatchProto";
option java_package = "com.google.watcher.v1";

// ## API Overview
//
// [Watcher][] lets a client watch for updates to a named entity, such as a
// directory or database table. For each watched entity, the client receives a
// reliable stream of watch events, without re-ordering.
//
// Watching is done by sending an RPC to a service that implements the API. The
// argument to the RPC contains the name of the entity. The result stream
// consists of a sequence of Change messages that the service continues to
// send until the call fails or is cancelled.
//
// ## Data model
//
// This API assumes that each *entity* has a name and a
// set of *elements*, where each element has a name and a value. The
// entity's name must be a unique identifier within the service, such as
// a resource name. What constitutes an entity or element is
// implementation-specific: for example, a file system implementation
// might define an entity as either a directory or a file, and elements would be
// child files or directories of that entity.
//
// The Watch API allows a client to watch an entity E's immediate
// elements or the whole tree rooted at E. Elements are organized into
// a hierarchy ("" at the top; the rest follows the natural hierarchy of the
// namespace of elements that is being watched). For example, when
// recursively watching a filesystem namespace, X is an ancestor of
// X/Y and X/Y/Z).
//
// ## Watch request
//
// When a client makes a request to watch an entity, it can indicate
// whether it wants to receive the initial state of the entity, just
// new changes to the entity, or resume watching from a particular
// point in a previous watch stream, specified with a `resume_marker` value.
// It can also indicate whether it wants to watch only one entity or all
// entities in the subtree rooted at a particular entity's name.
//
// On receiving a watch request for an entity, the server sends one or more
// messages to the client. The first message informs the client that the server
// has registered the client's request: the instant of time when the
// client receives the event is referred to as the client's "watch
// point" for that entity.
//
// ## Atomic delivery
//
// The response stream consists of a sequence of Change messages. Each
// message contains an `continued` bit. A sub-sequence of Change messages with
// `continued=true` followed by a Change message with `continued=false` forms an
// *atomic group*. Systems that support multi-element atomic updates may
// guarantee that all changes resulting from a single atomic
// update are delivered in the same atomic group. It is up to the
// documentation of a particular system that implements the Watch API to
// document whether or not it supports such grouping. We expect that most
// callers will ignore the notion of atomic delivery and the `continued` bit,
// i.e., they will just process each Change message as it is received.
//
// ## Batching
//
// Multiple Change messages may be grouped into a single ChangeBatch message
// to reduce message transfer overhead. A single ChangeBatch may contain many
// atomic groups, or a single atomic group may be split across many
// ChangeBatch messages.
//
// ## Initial State
//
// The first atomic group delivered by a watch call is special. It is
// delivered as soon as possible and contains the initial state of the
// entity being watched. The client should consider itself caught up
// after processing this first atomic group.
//
// The messages in the first atomic group will either refer to the
// entity itself (`Change.element` == "") or to elements inside the
// entity (`Change.element` != ""). Here are the cases to consider:
//
// 1. `resume_marker` is "" or not specified: For every element P
//    (including the entity itself) that exists, there will be at least
//    one message delivered with element == P and the last such message
//    will contain the current state of P. For every element Q
//    (including the entity itself) that does not exist, either no
//    message will be delivered, or the last message for Q will have
//    state == DOES_NOT_EXIST. At least one message for element="" will
//    be delivered.
//
// 2. `resume_marker` == "now": there will be exactly one message with
//    element = "" and state INITIAL_STATE_SKIPPED. The client cannot
//    assume whether or not the entity exists after receiving this
//    message.
//
// 3. `resume_marker` has a value R from a preceding watch call on this
//    entity: The same messages as described in (1) will be delivered to
//    the client, except that any information implied by messages received
//    on the preceding call up to and including R may not be
//    delivered. The expectation is that the client will start with state
//    it had built up from the preceding watch call, apply the changes
//    received from this call, and build an up-to-date view of the entity
//    without having to fetch a potentially large amount of information
//    that has not changed. Note that some information that had already
//    been delivered by the preceding call might be delivered again.
//
// ## Ordering and Reliability
//
// The Change messages that apply to a particular element of the entity are
// delivered eventually in order without loss for the duration of the RPC. Note
// however that if multiple Changes apply to the same element, the
// implementation is free to suppress them and deliver just the last one. The
// underlying system must provide the guarantee that any relevant update
// received for an entity E after a client's watch point for E MUST be delivered
// to that client.
//
// These tight guarantees allow for the following simplifications in the client:
//
//   1. The client does not need to have a separate polling loop to make up for
//      missed updates.
//
//   2. The client does not need to manage timestamps/versions manually; the
//      last update delivered corresponds to the eventual state of the entity.
//
// Example: a calendar entry may have elements named { "starttime", "endtime",
// "attendees" } with corresponding values or it may have a single element name
// "entry" with a serialized proto for the calendar entry.
//
// ## Ordering constraints for parents/descendants
//
// The Watch API provides guarantees regarding the order in which
// messages for a parent and its descendants are delivered:
//
// 1. The creation of an ancestor (i.e., the first EXISTS message for
//    the ancestor) is reported before the creation of any of its
//    descendants.
//
// 2. The deletion of an ancestor (via a DOES_NOT_EXIST message)
//    implies the deletion of all its descendants. The service will
//    not deliver any messages for the descendants until the parent
//    has been recreated.

// The service that a client uses to connect to the watcher system.
// The errors returned by the service are in the canonical error space,
// see [google.rpc.Code][].
service Watcher {
  // Start a streaming RPC to get watch information from the server.
  rpc Watch(Request) returns (stream ChangeBatch) {
    option (google.api.http) = {
      get: "/v1/watch"
    };
  }
}

// The message used by the client to register interest in an entity.
message Request {
  // The `target` value **must** be a valid URL path pointing to an entity
  // to watch. Note that the service name **must** be
  // removed from the target field (e.g., the target field must say
  // "/foo/bar", not "myservice.googleapis.com/foo/bar"). A client is
  // also allowed to pass system-specific parameters in the URL that
  // are only obeyed by some implementations. Some parameters will be
  // implementation-specific. However, some have predefined meaning
  // and are listed here:
  //
  //  * recursive = true|false [default=false]
  //    If set to true, indicates that the client wants to watch all elements
  //    of entities in the subtree rooted at the entity's name in `target`. For
  //    descendants that are not the immediate children of the target, the
  //    `Change.element` will contain slashes.
  //
  //    Note that some namespaces and entities will not support recursive
  //    watching. When watching such an entity, a client must not set recursive
  //    to true. Otherwise, it will receive an `UNIMPLEMENTED` error.
  //
  // Normal URL encoding must be used inside `target`.  For example, if a query
  // parameter name or value, or the non-query parameter portion of `target`
  // contains a special character, it must be %-encoded.  We recommend that
  // clients and servers use their runtime's URL library to produce and consume
  // target values.
  string target = 1;

  // The `resume_marker` specifies how much of the existing underlying state is
  // delivered to the client when the watch request is received by the
  // system. The client can set this marker in one of the following ways to get
  // different semantics:
  //
  // *   Parameter is not specified or has the value "".
  //     Semantics: Fetch initial state.
  //     The client wants the entity's initial state to be delivered. See the
  //     description in "Initial State".
  //
  // *   Parameter is set to the string "now" (UTF-8 encoding).
  //     Semantics: Fetch new changes only.
  //     The client just wants to get the changes received by the system after
  //     the watch point. The system may deliver changes from before the watch
  //     point as well.
  //
  // *   Parameter is set to a value received in an earlier
  //     `Change.resume_marker` field while watching the same entity.
  //     Semantics: Resume from a specific point.
  //     The client wants to receive the changes from a specific point; this
  //     value must correspond to a value received in the `Change.resume_marker`
  //     field. The system may deliver changes from before the `resume_marker`
  //     as well. If the system cannot resume the stream from this point (e.g.,
  //     if it is too far behind in the stream), it can raise the
  //     `FAILED_PRECONDITION` error.
  //
  // An implementation MUST support an unspecified parameter and the
  // empty string "" marker (initial state fetching) and the "now" marker.
  // It need not support resuming from a specific point.
  bytes resume_marker = 2;
}

// A batch of Change messages.
message ChangeBatch {
  // A list of Change messages.
  repeated Change changes = 1;
}

// A Change indicates the most recent state of an element.
message Change {
  // A reported value can be in one of the following states:
  enum State {
    // The element exists and its full value is included in data.
    EXISTS = 0;

    // The element does not exist.
    DOES_NOT_EXIST = 1;

    // Element may or may not exist. Used only for initial state delivery when
    // the client is not interested in fetching the initial state. See the
    // "Initial State" section above.
    INITIAL_STATE_SKIPPED = 2;

    // The element may exist, but some error has occurred. More information is
    // available in the data field - the value is a serialized Status
    // proto (from [google.rpc.Status][])
    ERROR = 3;
  }

  // Name of the element, interpreted relative to the entity's actual
  // name. "" refers to the entity itself. The element name is a valid
  // UTF-8 string.
  string element = 1;

  // The state of the `element`.
  State state = 2;

  // The actual change data. This field is present only when `state() == EXISTS`
  // or `state() == ERROR`. Please see
  // [google.protobuf.Any][google.protobuf.Any] about how to use the Any type.
  google.protobuf.Any data = 6;

  // If present, provides a compact representation of all the messages that have
  // been received by the caller for the given entity, e.g., it could be a
  // sequence number or a multi-part timestamp/version vector. This marker can
  // be provided in the Request message, allowing the caller to resume the
  // stream watching at a specific point without fetching the initial state.
  bytes resume_marker = 4;

  // If true, this Change is followed by more Changes that are in the same group
  // as this Change.
  bool continued = 5;
}