Websocket server » History » Revision 6
« Previous |
Revision 6/12
(diff)
| Next »
Peter Amstutz, 08/19/2016 02:23 AM
Websocket server¶
(early draft)
- Table of contents
- Websocket server
Background¶
The Rails API server can function as a websocket server. Clients (notably Workbench, arv-mount, arv-ws) use it to listen for events without polling.
Problems with current implementation:- Unreliable. See #9427, #8277
- Resource-heavy (one postgres connection per connected client, uses lots of memory)
- Logging is not very good
- Updates look like database records instead of API responses (e.g., computed fields are missing, collection manifest_text has no signatures)
- Offers an API for catching up on missed events after disconnecting/reconnecting, but this API (let alone the code) isn't enough to offer a "don't miss any events, don't send any events twice" guarantee. See #9388
Desired features¶
Monotonically increasing event IDs, so clients can (meaningfully) request "all matching events since X"
Design sketch (TC)¶
New server, written in Go.
One goroutine per connected client.
One database connection receiving notifications about new logs. (Possibly still N database connections serving "catch-up" messages to N clients.)
Design sketch (PA)¶
When client connects, it can request a new session (with event filter), or asks to resume an existing session from a given event id.
Each session has a session id and is associated with a user, an event channel, an event queue, event filters, and exactly one websocket connection.
Clients can create multiple sessions on the same websocket. Resuming a session associates the session to a new websocket connection (must be same user). Resuming a session replays any queued events occurring after the given event id.
Orderly websocket disconnects tear down the session. Abrupt disconnects maintain the session for N minutes.
NOTIFY sends full json-encoded record.
Websocket server database LISTEN receives NOTIFY, deserializes record, gets object_uuid
and object_owner_uuid
and determines the set of users who have permission to view the log record using in-memory cache of permissions graph.
Intersect the set of users who can view the record with the users associated with active sessions and adds the record to the queue for each session with the associated user.
The goroutine for session gets a new event on the event channel. It first applies the session filters to determine if the event should be propagated. (This should be a Go-based implementation of Arvados query filters and not touch the database.) If it passes filters, the event is assigned a session-specific sequence number, added to a queue, and can be sent to the websocket client.
The websocket client receives the event and sends an acknowledgement with the sequence number. The server receives the acknowledgement and removes the message from the queue.
Libraries¶
Websocket: PostgreSQL:- https://godoc.org/github.com/lib/pq via https://godoc.org/database/sql
- https://godoc.org/github.com/lib/pq#hdr-Notifications and https://godoc.org/github.com/lib/pq/listen_example
Obstacles¶
Related¶
It might be expedient to offload synchronization to some existing software that does this well.- Apache Zookeeper -- "Coordination services are notoriously hard to get right. They are especially prone to errors such as race conditions and deadlock. The motivation behind ZooKeeper is to relieve distributed applications the responsibility of implementing coordination services from scratch."
- Google Chubby paper
- NSQ http://nsq.io/
Updated by Peter Amstutz over 8 years ago · 12 revisions