Websocket v0 shim » History » Version 1
Tom Clegg, 11/03/2016 11:57 PM
1 | 1 | Tom Clegg | h1. Websocket v0 shim |
---|---|---|---|
2 | |||
3 | Objective: |
||
4 | * Go-based websocket server. |
||
5 | * Implement just enough of the existing Rails/Puma server's API so it can be dropped in as a replacement without breaking existing clients. |
||
6 | * Leave room to implement v1 [[Websocket server]] in the same server process, so new clients can use v1 while old clients continue using v0. |
||
7 | |||
8 | h1. Functional |
||
9 | |||
10 | h2. Endpoint |
||
11 | |||
12 | Provide v0 API at "/websocket". |
||
13 | |||
14 | h2. Subscription requests |
||
15 | |||
16 | <pre> |
||
17 | {"method":"subscribe", "last_log_id":12345, "filters":[["event_type","=","X"]]} |
||
18 | {"method":"subscribe", "last_log_id":12345} |
||
19 | {"method":"subscribe"} |
||
20 | </pre> |
||
21 | |||
22 | Ignore filters requested by the client. Just send all events (subject to permissions). |
||
23 | |||
24 | *Optional(?):* Implement event_type filters as used by arv-mount. Otherwise, every arv-mount process will receive a lot of job/container log data that it can't use. |
||
25 | |||
26 | If last_log_id is given, |
||
27 | * start listening for new events (but don't process any yet) |
||
28 | * load old rows from the logs table with @id >= last_log_id@, and process them as if they were new |
||
29 | * note the largest ID seen in the old rows (if any); save this in last_log_id |
||
30 | * process new events as they arrive, but skip events with @id <= last_log_id@ |
||
31 | |||
32 | Ignore "unsubscribe" messages. |
||
33 | |||
34 | h2. Event messages |
||
35 | |||
36 | Send only these fields from each event/log: |
||
37 | * id |
||
38 | * object_uuid |
||
39 | * object_kind |
||
40 | * object_owner_uuid |
||
41 | * properties (only if object is a container or job) |
||
42 | * created_at |
||
43 | |||
44 | h2. Slow clients |
||
45 | |||
46 | Allocate a finite sized buffer/channel of events for each connected client. If a client receives events too slowly and its buffer fills up: |
||
47 | * print a log message. |
||
48 | * (if possible) send an error message to the client. |
||
49 | * terminate the connection. |
||
50 | |||
51 | h2. Logging |
||
52 | |||
53 | Print JSON-formatted log entries on stderr. |
||
54 | |||
55 | Print a log entry when a client connects. |
||
56 | |||
57 | Print a log entry when a client disconnects. Show counters for |
||
58 | * Number of events sent |
||
59 | * Number of bytes sent |
||
60 | |||
61 | h1. Implementation |
||
62 | |||
63 | h2. Database access |
||
64 | |||
65 | Connect directly to PostgreSQL to receive event notifications. |
||
66 | |||
67 | h2. Permission |
||
68 | |||
69 | Defer to the REST API for permission checks. |
||
70 | |||
71 | Before sending an event to a subscriber, check whether the subscriber's token is able to retrieve the object_uuid referenced in the event. |
||
72 | |||
73 | To check permission, perform a HEAD request for the event's object_uuid, using the subscriber's token. |
||
74 | |||
75 | Maintain a permission cache {(token, object_uuid) → bool}. When the cache grows bigger than the configured number of entries (default 128K?), clear it and emit a log message. |
||
76 | |||
77 | h2. Configuration |
||
78 | |||
79 | Configuration will include |
||
80 | * PostgreSQL connection info/credentials |
||
81 | * API server endpoint (use arvados.Client like keep-balance et al.) |
||
82 | * Maximum connection buffer size (buffered events per connection) |
||
83 | * Maximum concurrent connections |