Events API » History » Version 2
Tom Clegg, 10/19/2016 10:24 AM
| 1 | 1 | Tom Clegg | h1. Events API |
|---|---|---|---|
| 2 | |||
| 3 | (draft) |
||
| 4 | |||
| 5 | {{toc}} |
||
| 6 | |||
| 7 | See also: [[Websocket server]] |
||
| 8 | |||
| 9 | h1. Purpose |
||
| 10 | |||
| 11 | The Events API serves to notify processes about events that interest them _as soon as possible after those events happen_. |
||
| 12 | |||
| 13 | (The history of events that have happened in the past is also interesting, but that's addressed by the Logs API, not the Events API.) |
||
| 14 | |||
| 15 | h1. Conceptual model |
||
| 16 | |||
| 17 | An event reports a change to the state of an object. |
||
| 18 | |||
| 19 | The fact that an object's state has changed is meaningful only when its previous state is known. For example, if a client asks "tell me the next time object X changes" at nearly the same time X changes, the response depends on whether the request arrives before or after the change occurs. |
||
| 20 | |||
| 21 | Therefore, the Events API should support operations like: |
||
| 22 | * "tell me the current state of X, and then notify me next time it changes" |
||
| 23 | * "tell me as soon as X differs from my cached copy that has Etag E" |
||
| 24 | |||
| 25 | An "event stream" is a sequence of events about an object, starting from an implicit or explicit known state. |
||
| 26 | |||
| 27 | h1. Essential features |
||
| 28 | |||
| 29 | h2. Multiple streams |
||
| 30 | |||
| 31 | The Events API supports multiplexing event streams on a single connection. The cost of setting up and maintaining an event channel can be non-trivial, and the sequence of events concerning multiple related objects may be significant. |
||
| 32 | |||
| 33 | It is possible to add and remove event streams on an existing connection, without interrupting other streams. |
||
| 34 | |||
| 35 | It is permitted to hold a connection open with no event streams, but the server may close such connections after some time threshold. |
||
| 36 | |||
| 37 | h2. Delivery guarantees |
||
| 38 | |||
| 39 | In general, the Events API cannot guarantee that every event will be delivered. |
||
| 40 | |||
| 41 | However, there are specific cases where it is possible to detect missed events and notify the client. |
||
| 42 | |||
| 43 | If some events are dropped but the event stream is still open (for example, a server-side buffer overflows when a client is receiving data too slowly) the stream must indicate this to the client as soon as possible, and no later than the next event. |
||
| 44 | * The "missed events" signal does not necessarily specify the number of missed events. |
||
| 45 | * The server is permitted to send a "missed events" signal even if no events were missed. |
||
| 46 | |||
| 47 | Depending on the application, a client might respond to a "missed events" signal by |
||
| 48 | * restarting the affected streams immediately |
||
| 49 | * restarting the affected streams only if they stay silent for some timeout period |
||
| 50 | * doing nothing |
||
| 51 | * hanging up |
||
| 52 | |||
| 53 | h2. Event message content |
||
| 54 | |||
| 55 | Each event includes the UUID and Etag of the changed object. |
||
| 56 | |||
| 57 | If requested by the client, and supported by the server, events may also include other object attributes. |
||
| 58 | |||
| 59 | h1. Additional features |
||
| 60 | |||
| 61 | h2. Event sequence |
||
| 62 | |||
| 63 | With the current API server, it may be possible to update an object twice in quick succession such that the modification timestamps are out of order: i.e., the current state of object X has modification time T1, even though the same object previously had modification time T2>T1. If this occurs, the Events API must return the T2 update before the T1 update (or not return the T2 update at all). |
||
| 64 | |||
| 65 | In order to support delivery mechanisms where messages are re-ordered in transit, the Events API should assign a strictly increasing integer ID to each event sent over a given connection. Client pseudocode: |
||
| 66 | |||
| 67 | <pre> |
||
| 68 | receiveEvent(id, uuid, newEtag): |
||
| 69 | if lastID[uuid] > id: |
||
| 70 | # already received a newer update for this object |
||
| 71 | return |
||
| 72 | currentEtag[uuid] = newEtag |
||
| 73 | lastID[uuid] = id |
||
| 74 | </pre> |
||
| 75 | |||
| 76 | Note these IDs are connection-specific: they cannot be used to reconnect and resume an event stream. |
||
| 77 | |||
| 78 | h2. Server-side event filters |
||
| 79 | |||
| 80 | Some clients will only be interested in a subset of possible changes. For example, a pipeline runner wants to know as soon as a container's "state" attribute changes, but might not care about other changes like "priority" or "progress". |
||
| 81 | |||
| 82 | Possible API features for reducing unnecessary work and network traffic: |
||
| 83 | # Allow clients to describe which attributes are interesting, e.g., @"select":["state"]@ |
||
| 84 | # With each event, provide the list of changed attributes, e.g., @"changed":["state","output","log"]@, but not the attribute values themselves |
||
| 85 | |||
| 86 | These features might be tricky to implement efficiently for attributes that are computed on the fly. |
||
| 87 | |||
| 88 | h2. Null stream |
||
| 89 | |||
| 90 | To simplify implementation of clients that subscribe to event streams but also retrieve some objects without listening for events, a client should be able to use the Events API to retrieve the current state of an object without subscribing to the object's event stream. |
||
| 91 | 2 | Tom Clegg | |
| 92 | h2. Ownership-change events |
||
| 93 | |||
| 94 | Some clients need to know when an object is added or removed from a project. |
||
| 95 | |||
| 96 | When an object's owner_uuid changes, this event should be sent to: |
||
| 97 | # all clients subscribed to the object itself |
||
| 98 | # all clients subscribed to the old owner_uuid |
||
| 99 | # all clients subscribed to the new owner_uuid |
||
| 100 | |||
| 101 | Likewise, subscribing to stream X should cause clients to receive messages when a new object is created with owner_uuid=X, and when an object with owner_uuid=X is deleted. |