Skip to content

Commit

Permalink
Add example of running multiple zerogw on single socket/port/fd
Browse files Browse the repository at this point in the history
  • Loading branch information
tailhook committed Aug 19, 2012
1 parent 37a4f56 commit 96a941c
Show file tree
Hide file tree
Showing 4 changed files with 149 additions and 0 deletions.
8 changes: 8 additions & 0 deletions examples/tabbedchat/README.rst
Expand Up @@ -13,6 +13,14 @@ Which runs multiple processes of python and zerogw, to show how it could be
scaled. But you need to turn sockets into tcp ones to scale it to multiple
machines, and also fix redis config which is awfully slow for testing purposes.

There is also::

./single_socket.sh

Which is merely same as ``scale.sh``, but running multiple zerogw instances
on single port.


You can also find this chat online at http://tabbedchat.zerogw.com


Expand Down
34 changes: 34 additions & 0 deletions examples/tabbedchat/single_port_zerogw.py
@@ -0,0 +1,34 @@
#!/usr/bin/env python3

"""
This script is intended to run multiple zerogw instances with single shared
port/socket. This works by creating a socket externally, and pasing it as
a file descriptor to all zerogw instances, during exec.
You must configure zerogw to use the file descriptor to run correctly
(example zerogw_fd.yaml does this)
"""

import socket
import os
import sys

# Let's open shared socket
zgwsock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
zgwsock.bind(('0.0.0.0', 8000))
zgwsock.listen(100000)
zgwsock.setblocking(False) # Crucial for zerogw with older libwebsite

# Now make it file descriptor zero
os.dup2(zgwsock.fileno(), 0)

# Now close old socket (we have dup as fd zero)
zgwsock.close()

# Each zerogw has it's own socket directory, so we use pass directory
# names as arguments and create a zerogw instance per directory
for dir in sys.argv[1:]:
if dir != sys.argv[-1]: # last instance is our process, no more forks
if os.fork(): # parent continues to fork processes
continue
os.execlp('zerogw', 'zerogw', '-c', 'zerogw_fd.yaml', '-Ddir=' + dir)
51 changes: 51 additions & 0 deletions examples/tabbedchat/single_socket.sh
@@ -0,0 +1,51 @@
#!/bin/sh

# Setting up signal handlers
# All this code is needed to do not leave dangling children
killchildren() {
if [ "x$(jobs)" == "x" ]; then
exit 0
fi
trap killchildren 0 1 2 3 15
kill $(jobs -p) 2>/dev/null
}
trap killchildren 0 1 2 3 15

# running several redis instances is given as exercise for the reader
# basically you just need more python code for that
redis-server redis.conf &

# We provide each zerogw instance a separate directory for zeromq sockets
# because zeromq sockets are bound, but use special startup script for
# running them on single port
mkdir -p ./run/z{1,2,3} 2> /dev/null
# passing three dirs means start three zerogw instances one per dir
python single_port_zerogw.py ./run/z1 ./run/z2 ./run/z3 &

# because of zeromq features, and because we are using bind sockets in zerogw
# side (which is most useful use case), we can run any number of backends
# with equal configuration
# BTW, storing data in redis also helps
for i in $(seq 0 4); do
python3 -m tabbedchat \
--auth-connect "ipc://./run/z1/auth.sock" \
--auth-connect "ipc://./run/z2/auth.sock" \
--auth-connect "ipc://./run/z3/auth.sock" \
--chat-connect "ipc://./run/z1/chat.sock" \
--chat-connect "ipc://./run/z2/chat.sock" \
--chat-connect "ipc://./run/z3/chat.sock" \
--output-connect "ipc://./run/z1/output.sock" \
--output-connect "ipc://./run/z2/output.sock" \
--output-connect "ipc://./run/z3/output.sock" \
&
done

echo "========================================================================"
echo "You can now browse:"
echo " http://localhost:8000/"
echo "Depending on your luck you will hit different zerogw instance each time"
echo "NOTE: Long polling (websocket fallback) doesn't work correctly"
echo "WARNING: Danging zerogw processes may exist after stopping"
echo "========================================================================"

while ! wait; do true; done;
56 changes: 56 additions & 0 deletions examples/tabbedchat/zerogw_fd.yaml
@@ -0,0 +1,56 @@
# This is example of configuration file with listening socket passed by
# file descriptor. It's useful to bind to port 80 either using openport or
# using procboss, and to run multiple instances of zerogw on single port
# (see single_socket.sh)

# Zerogw's configuration library allows you to override variables
# from a command line, so we create one, to be able to override port and socket
# directory. See ./scale.sh for example of how to use it
# (we use yaml anchors and $-style variables interchangeably with coyaml)
_dir: &dir ./run

Server:
zmq-io-threads: 1
disk-io-threads: 1
listen:
- host: 0.0.0.0
port: 8000
fd: 0 # File descriptor number zero is used instead of host/port
control:
socket:
- !zmq.Bind ipc://$dir/zerogw-ctl
error-log:
level: 3
warning-timeout: 300
filename: ./run/error.log

Routing:
routing: !Prefix ~
routing-by: !Uri ~
map:
"/":
static:
enabled: yes
root: ./public
restrict-root: no # bad for production
index-file: index.html
"/ws*":
websocket:
enabled: yes
forward: !zmq.Push
- !zmq.Bind "ipc://$dir/auth.sock"
named-outputs:
chat: !zmq.Push
sync-interval: 10 # too low, for example purposes
=:
- !zmq.Bind "ipc://$dir/chat.sock"
subscribe: !zmq.Pull
- !zmq.Bind "ipc://$dir/output.sock"
children:
- match:
- "/js/*"
- "/css/*"
static:
enabled: yes
root: ./public
restrict-root: no # bad for production

0 comments on commit 96a941c

Please sign in to comment.