-
Notifications
You must be signed in to change notification settings - Fork 13
Websocket API
#What are WebSockets WebSockets defines a bi-directional web communication that makes it possible to open an interactive session between the server and the client’s browser. The server and the client can both send messages and receive event-driven responses. Instead of polling the server for an update, the server can push notifications whenever there is an update in the system.
#How does it work
##Client Side The connection to server can be established by creating a WebSocket object which has different functions. Once a message containing information about the status, the name and the UUID of the updated model, it will call the corresponding function to fetch the specific resource.
###1. Handshake
The server has first to listen for incoming messages using standard TCP socket and the handshake is the connection from HTTP to WS. Once the connection is established, the server and the client can communicate through socket message. The connection can be opened on the client side using
var ws = new WebSocket('ws://' + location.host + '/ws/rodan?subscribe-broadcast&publish-broadcast&echo');
####Status code
Each WebSocket object has a property .readyState
that defines the status of the object
-0 Connecting
-1 Opened
-2 Closing
-3 Closed
The connection is ready to communicate only when the status code equals to 1.
####ws.onopen
Executes codes as soon as WebSocket is connected and can be used to set interval for heartbeats.
ws.onopen = function on_open() {
console.log("Websocket connected");
}
###2. Exchange Data
The WebSocket object has different functions including .open
, .onmessage
, .onerror
, and .onclose
.
In order to receive messages, the function .onmessage
is used.
####Receiving messages with ws.onmessage
Executes codes when a socket message is received and can be used to check if any heartbeat messages are missed.
ws.onmessage = function on_message(e) {
if (e.data === heartbeat_msg) {
missed_heartbeats = 0;
return;
}
console.log("Received: " + e.data);
}
####Sending messages with ws.send
ws.send("message_string")
###3. Heartbeats
After the handshake, the server will send a ping to the client and the client replies with a pong. A ping or pong is a control frame in order to check if the client is still connected. If too many heartbeats are missed, the connection will close automatically.
The heartbeat configuration is in settings.py
file, where the heartbeat message can be customized.
WS4REDIS_HEARTBEAT = '--heartbeat--'
###4. Error Display
The WebSocket object has an EventListener for any encountered error.
####ws.onerror
Displays any error with the WebSockets.
ws.onerror = function on_error(e) {
console.error(e);
}
###5. Close connection The connection can be closed when the client or the server sends a control frame such as the heartbeats with data containing a specified control sequence to begin the closing handshake.
####ws.onclose
Executes codes when the connection is closed and can be used to check if the closing event was clean.
ws.onclose = function on_close(e) {
if (e.wasClean) {
console.log("Connection was closed properly");
} else {
console.log ("Connection not properly closed");
}
console.log("Code: " + e.code + "Reason: " + e.reason);
}
##Server Side
###Dependencies and installation
####Redis
Redis is a flexible, open-source, key value data store. It allows the user to store vast amounts of data without the limits of a relational database. Redis is used as a message queue and is run side by side with Django.
To install Redis, download the package from here:
wget http://download.redis.io/redis-stable.tar.gz
tar xvzf redis-stable.tar.gz
cd redis-stable
make
To start Redis server, go into the Redis directory and do:
$> src/redis-server
Once the server is started, you can test it by starting the program redis-cli
which can be used to send messages to Redis. When sending a PING
command, the server will answer with a PONG
if it is working properly.
$> redis-cli
redis 127.0.0.1:6379> PING
redis 127.0.0.1:6379> PONG
####ws4redis
Websocket for Redis (ws4redis) allows uni- and bidirectional communication from the client to the server and vice versa. Each websocket is identified by the part of the URL which follows the prefix /ws/. Use different uniform locators to distinguish between unrelated communication channels.
To install, first make sure that Redis server is running, then do:
pip install django-websocket-redis
To add heartbeat configuration, a setting should be added WS4REDIS_HEARTBEAT = '--heartbeat--'
.
####Psycopg
Psycopg is a PostgreSQL adapter for the Python programming language. It is a wrapper for the libpq, the official PostgreSQL client library. And Psycopg2 package is the mature implementation of the adapter.
If it is not already installed, install the package with:
$> pip install psycopg2
###Post-update trigger in Postgres database
Instead of the server polling for any update request from the client, the update notification is 'pushed' from the server side by adding triggers inside Postgres tables containing Rodan models. A signal is sent each time an INSERT
or UPDATE
action is performed on a table containing the trigger. Specifically, looping through the Rodan model tables, the triggers are first destroyed if they already exist, and then they are re-created.
See this file.
###Publish Redis socket messages
Every time a signal is received from the post-update trigger, a message containing information about the status of update, the model name and the UUID of the model instance is broadcasted to all subscribed clients through Redis.
Redis connection can be opened with:
r = redis.StrictRedis(REDIS_HOST, REDIS_PORT, DB)
where REDIS_HOST
, REDIS_PORT
, and DB
are specified in the settings_production.py
.
Once the connection is opened, messages can be broadcasted.
r.publish('rodan:broadcast:rodan', 'message_string')
###Post-migrate signal
The process of creating triggers on database tables is performed after receiving the post-migrate signal from Django, ie. triggers will be destroyed and re-created each time this command is executed:
(rodan-env)$> python manage.py migrate
#Stress Testing
##Dependancies and installation
Thor is needed for stress testing. Make sure that Node.js is installed on your system. Then, install the module using
$> npm install -g thor
##Testing
Then, stress tests can be run by running
$> ~/Rodan/rodan/test/test_load.sh -a[options] -n[options] -s[options]
Running the command will diplay a help menu.
$> ~/Rodan/rodan/test/test_load.sh -h
Options:
-a Number of connections to test on, if unspecified, 10000 connections will be tested
-n Number of messages to be sent per connection
-s Name of the server, eg. rodan.simssa.ca. if unspecified, server will be localhost
-h Show help instructions
The test results will be stored in the directory ~/Rodan/rodan/test/test_log
.
- Repository Structure
- Working on Rodan
- Testing Production Locally
- Working on Interactive Classifier
- Job Queues
- Testing New Docker Images
- Set up Environment Variables
- Set up SSL with Certbot
- Set up SSH with GitHub
- Deploying on Staging
- Deploying on Production
- Import Previous Data