redis-sentinel-pool 0.1.0

An async Redis Sentinel-aware connection pool built on top of redis-rs and bb8, with transparent master failover.
Documentation
# Redis Sentinel 3 节点演练环境
#
# 拓扑:
#   redis-1 (master,  6379)   ┐
#   redis-2 (replica, 6380)   ├── 三个 sentinel: 26379 / 26380 / 26381 (quorum=2)
#   redis-3 (replica, 6381)   ┘
#
# 关键设计:
#   所有 redis / sentinel 容器共享 `net` 服务的 network namespace
#   (network_mode: "service:net")。这样:
#     1. 容器内部互相通过 127.0.0.1 + 不同端口直连 (sentinel 监控、replicaof 都用 127.0.0.1);
#     2. 宿主机也通过 127.0.0.1 + 同样的端口直连;
#     3. sentinel 向客户端返回的 master/replica 地址天然就是 127.0.0.1,
#        宿主机上 cargo run --example failover 无需任何 hosts 改写、
#        无需 host networking、无需 announce-ip 各种 trick。
#
# 启动: docker compose -f docker/docker-compose.yml up -d
# 验证: redis-cli -p 26379 SENTINEL get-master-addr-by-name mymaster
# 演练: redis-cli -p 26379 SENTINEL FAILOVER mymaster

services:
  # 仅用于持有 network namespace + 端口映射,本身不跑任何业务进程。
  net:
    image: alpine:3.20
    container_name: redis-sentinel-net
    command: ["sh", "-c", "trap 'exit 0' TERM; while :; do sleep 1; done"]
    ports:
      - "6379:6379"
      - "6380:6380"
      - "6381:6381"
      - "26379:26379"
      - "26380:26380"
      - "26381:26381"
    healthcheck:
      test: ["CMD", "sh", "-c", "echo ok"]
      interval: 5s
      timeout: 2s
      retries: 3

  redis-1:
    image: redis:7.4-alpine
    container_name: redis-1
    network_mode: "service:net"
    depends_on:
      net:
        condition: service_healthy
    command:
      - redis-server
      - --port
      - "6379"
      - --bind
      - 0.0.0.0
      - --protected-mode
      - "no"
      - --appendonly
      - "yes"
      - --replica-announce-ip
      - 127.0.0.1
      - --replica-announce-port
      - "6379"
    healthcheck:
      test: ["CMD", "redis-cli", "-p", "6379", "PING"]
      interval: 3s
      timeout: 2s
      retries: 10

  redis-2:
    image: redis:7.4-alpine
    container_name: redis-2
    network_mode: "service:net"
    depends_on:
      redis-1:
        condition: service_healthy
    command:
      - redis-server
      - --port
      - "6380"
      - --bind
      - 0.0.0.0
      - --protected-mode
      - "no"
      - --appendonly
      - "yes"
      - --replicaof
      - 127.0.0.1
      - "6379"
      - --replica-announce-ip
      - 127.0.0.1
      - --replica-announce-port
      - "6380"
    healthcheck:
      test: ["CMD", "redis-cli", "-p", "6380", "PING"]
      interval: 3s
      timeout: 2s
      retries: 10

  redis-3:
    image: redis:7.4-alpine
    container_name: redis-3
    network_mode: "service:net"
    depends_on:
      redis-1:
        condition: service_healthy
    command:
      - redis-server
      - --port
      - "6381"
      - --bind
      - 0.0.0.0
      - --protected-mode
      - "no"
      - --appendonly
      - "yes"
      - --replicaof
      - 127.0.0.1
      - "6379"
      - --replica-announce-ip
      - 127.0.0.1
      - --replica-announce-port
      - "6381"
    healthcheck:
      test: ["CMD", "redis-cli", "-p", "6381", "PING"]
      interval: 3s
      timeout: 2s
      retries: 10

  sentinel-1:
    image: redis:7.4-alpine
    container_name: sentinel-1
    network_mode: "service:net"
    depends_on:
      redis-1:
        condition: service_healthy
      redis-2:
        condition: service_healthy
      redis-3:
        condition: service_healthy
    entrypoint: ["sh", "-c"]
    command:
      - |

        cat > /tmp/sentinel.conf <<'EOF'
        port 26379
        bind 0.0.0.0
        protected-mode no
        sentinel resolve-hostnames yes
        sentinel announce-ip 127.0.0.1
        sentinel announce-port 26379
        sentinel monitor mymaster 127.0.0.1 6379 2
        sentinel down-after-milliseconds mymaster 5000
        sentinel failover-timeout mymaster 10000
        sentinel parallel-syncs mymaster 1
        EOF
        exec redis-sentinel /tmp/sentinel.conf
    healthcheck:
      test: ["CMD", "redis-cli", "-p", "26379", "PING"]
      interval: 3s
      timeout: 2s
      retries: 10

  sentinel-2:
    image: redis:7.4-alpine
    container_name: sentinel-2
    network_mode: "service:net"
    depends_on:
      redis-1:
        condition: service_healthy
      redis-2:
        condition: service_healthy
      redis-3:
        condition: service_healthy
    entrypoint: ["sh", "-c"]
    command:
      - |

        cat > /tmp/sentinel.conf <<'EOF'
        port 26380
        bind 0.0.0.0
        protected-mode no
        sentinel resolve-hostnames yes
        sentinel announce-ip 127.0.0.1
        sentinel announce-port 26380
        sentinel monitor mymaster 127.0.0.1 6379 2
        sentinel down-after-milliseconds mymaster 5000
        sentinel failover-timeout mymaster 10000
        sentinel parallel-syncs mymaster 1
        EOF
        exec redis-sentinel /tmp/sentinel.conf
    healthcheck:
      test: ["CMD", "redis-cli", "-p", "26380", "PING"]
      interval: 3s
      timeout: 2s
      retries: 10

  sentinel-3:
    image: redis:7.4-alpine
    container_name: sentinel-3
    network_mode: "service:net"
    depends_on:
      redis-1:
        condition: service_healthy
      redis-2:
        condition: service_healthy
      redis-3:
        condition: service_healthy
    entrypoint: ["sh", "-c"]
    command:
      - |

        cat > /tmp/sentinel.conf <<'EOF'
        port 26381
        bind 0.0.0.0
        protected-mode no
        sentinel resolve-hostnames yes
        sentinel announce-ip 127.0.0.1
        sentinel announce-port 26381
        sentinel monitor mymaster 127.0.0.1 6379 2
        sentinel down-after-milliseconds mymaster 5000
        sentinel failover-timeout mymaster 10000
        sentinel parallel-syncs mymaster 1
        EOF
        exec redis-sentinel /tmp/sentinel.conf
    healthcheck:
      test: ["CMD", "redis-cli", "-p", "26381", "PING"]
      interval: 3s
      timeout: 2s
      retries: 10