# Scaling Socket.IO with Redis and Multiple Instances

Flask-SocketIO cannot use multiple workers in a single Gunicorn process (`gunicorn -w 4`), because Gunicorn's load balancer does not support sticky sessions. Session affinity is required: the same client must always hit the same server process.

**Solution:** Run multiple single-worker Gunicorn **instances** on different ports, put nginx with `ip_hash` in front, and use Redis as a message queue so instances can coordinate broadcasts and rooms.

## Requirements

- Redis running (e.g. `redis://localhost:6379/0`)
- `pip install redis` (in requirements.txt)
- nginx with `ip_hash` for sticky sessions

## Setup

### 1. Set Redis URL

In your environment or systemd service:

```bash
export REDIS_URL="redis://localhost:6379/0"
# or SOCKETIO_REDIS_URL for a different Redis instance
```

### 2. Run Multiple Gunicorn Instances

Each instance uses `-w 1` and binds to a different port:

Use `--forwarded-allow-ips=*` when nginx is not on loopback so `X-Forwarded-For` reaches Flask (see [nginx.md](nginx.md) client IP section).

```bash
# Instance 1 (port 8080)
gunicorn -k gevent -w 1 --forwarded-allow-ips=* -b 0.0.0.0:8080 app:app &

# Instance 2 (port 8081)
gunicorn -k gevent -w 1 --forwarded-allow-ips=* -b 0.0.0.0:8081 app:app &

# Instance 3 (port 8082)
gunicorn -k gevent -w 1 --forwarded-allow-ips=* -b 0.0.0.0:8082 app:app &

# Instance 4 (port 8083)
gunicorn -k gevent -w 1 --forwarded-allow-ips=* -b 0.0.0.0:8083 app:app
```

### 3. nginx with ip_hash

```nginx
upstream opengit_socketio {
    ip_hash;   # Sticky sessions — same client always to same backend
    server 127.0.0.1:8080;
    server 127.0.0.1:8081;
    server 127.0.0.1:8082;
    server 127.0.0.1:8083;
}

location /socket.io/ {
    proxy_pass http://opengit_socketio;
    proxy_http_version 1.1;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection $connection_upgrade;
    proxy_buffering off;
    proxy_cache off;
    proxy_read_timeout 300s;
    proxy_send_timeout 300s;
}

location / {
    proxy_pass http://opengit_socketio;
    # ... other proxy settings
}
```

### 4. systemd Template (Optional)

Create `/etc/systemd/system/opengit@.service`:

```ini
[Unit]
Description=OpenGit instance %i
After=network.target redis.service

[Service]
User=opengit
Group=opengit
WorkingDirectory=/path/to/opengit
Environment="REDIS_URL=redis://localhost:6379/0"
ExecStart=/path/to/venv/bin/gunicorn -k gevent -w 1 --forwarded-allow-ips=* -b 0.0.0.0:%i app:app
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
```

The template uses `%i` as the port (instance id = 8080, 8081, ...). Enable instances:

```bash
systemctl enable opengit@8080 opengit@8081 opengit@8082 opengit@8083
systemctl start opengit@8080 opengit@8081 opengit@8082 opengit@8083
```

## Summary

| Mode              | Workers | Redis | nginx      |
|-------------------|---------|-------|------------|
| Single instance   | -w 1    | No    | Optional   |
| Multiple instances| 4 × -w 1| Yes   | ip_hash    |
