| // 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; |
| } |