or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

async-support.mdcluster-support.mdconnection-management.mdcore-client.mddistributed-locking.mderror-handling.mdhigh-availability.mdindex.mdpipelines-transactions.mdpubsub-messaging.md

high-availability.mddocs/

0

# High Availability

1

2

Redis Sentinel provides high availability for Redis deployments through automatic failover, service discovery, and monitoring. Sentinel acts as a distributed system that monitors Redis master and replica instances and manages failover when needed.

3

4

## Capabilities

5

6

### Sentinel Client

7

8

Redis Sentinel client for connecting to Redis with automatic failover and service discovery.

9

10

```python { .api }

11

class Sentinel:

12

def __init__(

13

self,

14

sentinels: List[Tuple[str, int]],

15

min_other_sentinels: int = 0,

16

sentinel_kwargs: Optional[Dict[str, Any]] = None,

17

password: Optional[str] = None,

18

db: int = 0,

19

decode_responses: bool = False,

20

**kwargs

21

): ...

22

23

def discover_master(self, service_name: str) -> Tuple[str, int]: ...

24

25

def discover_slaves(self, service_name: str) -> List[Tuple[str, int]]: ...

26

27

def master_for(

28

self,

29

service_name: str,

30

redis_class: Type[Redis] = Redis,

31

connection_pool_class: Type[ConnectionPool] = SentinelConnectionPool,

32

**kwargs

33

) -> Redis: ...

34

35

def slave_for(

36

self,

37

service_name: str,

38

redis_class: Type[Redis] = Redis,

39

connection_pool_class: Type[ConnectionPool] = SentinelConnectionPool,

40

**kwargs

41

) -> Redis: ...

42

43

def execute_command(

44

self,

45

*args,

46

**kwargs

47

) -> Any: ...

48

```

49

50

### Sentinel Management Commands

51

52

Commands for managing and monitoring Sentinel instances and Redis services.

53

54

```python { .api }

55

def sentinel_masters(self) -> List[Dict[str, Any]]: ...

56

57

def sentinel_master(self, service_name: str) -> Dict[str, Any]: ...

58

59

def sentinel_slaves(self, service_name: str) -> List[Dict[str, Any]]: ...

60

61

def sentinel_sentinels(self, service_name: str) -> List[Dict[str, Any]]: ...

62

63

def sentinel_get_master_addr_by_name(self, service_name: str) -> Optional[Tuple[str, int]]: ...

64

65

def sentinel_reset(self, pattern: str) -> int: ...

66

67

def sentinel_failover(self, service_name: str) -> bool: ...

68

69

def sentinel_ckquorum(self, service_name: str) -> bool: ...

70

71

def sentinel_flushconfig(self) -> bool: ...

72

73

def sentinel_monitor(

74

self,

75

service_name: str,

76

ip: str,

77

port: int,

78

quorum: int

79

) -> bool: ...

80

81

def sentinel_remove(self, service_name: str) -> bool: ...

82

83

def sentinel_set(self, service_name: str, option: str, value: Any) -> bool: ...

84

```

85

86

### Sentinel Connection Classes

87

88

Specialized connection pool and connection classes for Sentinel-managed Redis instances.

89

90

```python { .api }

91

class SentinelConnectionPool(ConnectionPool):

92

def __init__(

93

self,

94

service_name: str,

95

sentinel_manager: SentinelManager,

96

**kwargs

97

): ...

98

99

def get_master_address(self) -> Tuple[str, int]: ...

100

101

def rotate_slaves(self) -> None: ...

102

103

class SentinelManagedConnection(Connection):

104

def __init__(

105

self,

106

**kwargs

107

): ...

108

109

class SentinelManagedSSLConnection(SSLConnection):

110

def __init__(

111

self,

112

**kwargs

113

): ...

114

```

115

116

## Usage Examples

117

118

### Basic Sentinel Setup

119

120

```python

121

import redis

122

from redis.sentinel import Sentinel

123

124

# Configure Sentinel connections

125

sentinels = [

126

('localhost', 26379),

127

('localhost', 26380),

128

('localhost', 26381)

129

]

130

131

# Create Sentinel instance

132

sentinel = Sentinel(sentinels, socket_timeout=0.1)

133

134

# Discover master and slaves

135

master_address = sentinel.discover_master('mymaster')

136

slave_addresses = sentinel.discover_slaves('mymaster')

137

138

print(f"Master: {master_address}")

139

print(f"Slaves: {slave_addresses}")

140

```

141

142

### Connecting to Redis via Sentinel

143

144

```python

145

from redis.sentinel import Sentinel

146

147

# Setup Sentinel

148

sentinels = [('localhost', 26379), ('localhost', 26380), ('localhost', 26381)]

149

sentinel = Sentinel(sentinels, socket_timeout=0.1)

150

151

# Get Redis master client

152

master = sentinel.master_for('mymaster', socket_timeout=0.1)

153

154

# Get Redis slave client for read operations

155

slave = sentinel.slave_for('mymaster', socket_timeout=0.1)

156

157

# Write to master

158

master.set('key', 'value')

159

160

# Read from slave

161

value = slave.get('key')

162

print(f"Value from slave: {value}")

163

```

164

165

### Sentinel with Authentication

166

167

```python

168

from redis.sentinel import Sentinel

169

170

# Sentinel with password for Redis instances

171

sentinels = [('localhost', 26379), ('localhost', 26380), ('localhost', 26381)]

172

173

sentinel = Sentinel(

174

sentinels,

175

socket_timeout=0.1,

176

password='redis_password', # Password for Redis instances

177

sentinel_kwargs={

178

'password': 'sentinel_password' # Password for Sentinel instances

179

}

180

)

181

182

# Connect to authenticated Redis

183

master = sentinel.master_for('mymaster', password='redis_password')

184

slave = sentinel.slave_for('mymaster', password='redis_password')

185

```

186

187

### Advanced Sentinel Configuration

188

189

```python

190

from redis.sentinel import Sentinel

191

from redis import Redis

192

193

# Custom Sentinel configuration

194

sentinels = [('localhost', 26379), ('localhost', 26380), ('localhost', 26381')]

195

196

sentinel = Sentinel(

197

sentinels,

198

min_other_sentinels=1, # Require at least 1 other sentinel

199

socket_timeout=0.1,

200

socket_connect_timeout=0.1,

201

socket_keepalive=True,

202

retry_on_timeout=True,

203

decode_responses=True

204

)

205

206

# Get Redis clients with custom settings

207

master = sentinel.master_for(

208

'mymaster',

209

redis_class=Redis,

210

socket_timeout=0.1,

211

socket_connect_timeout=0.1,

212

socket_keepalive=True,

213

retry_on_timeout=True,

214

max_connections=20,

215

health_check_interval=30

216

)

217

218

slave = sentinel.slave_for(

219

'mymaster',

220

redis_class=Redis,

221

socket_timeout=0.1,

222

socket_connect_timeout=0.1,

223

socket_keepalive=True,

224

retry_on_timeout=True,

225

max_connections=20,

226

health_check_interval=30

227

)

228

```

229

230

### Monitoring Sentinel State

231

232

```python

233

from redis.sentinel import Sentinel

234

235

sentinels = [('localhost', 26379), ('localhost', 26380), ('localhost', 26381)]

236

sentinel = Sentinel(sentinels)

237

238

# Get all masters managed by Sentinel

239

masters = sentinel.sentinel_masters()

240

for master in masters:

241

print(f"Master: {master['name']} at {master['ip']}:{master['port']}")

242

print(f"Status: {master['flags']}")

243

print(f"Slaves: {master['num-slaves']}")

244

print(f"Sentinels: {master['num-other-sentinels']}")

245

246

# Get specific master info

247

master_info = sentinel.sentinel_master('mymaster')

248

print(f"Master info: {master_info}")

249

250

# Get slaves for a master

251

slaves = sentinel.sentinel_slaves('mymaster')

252

for slave in slaves:

253

print(f"Slave: {slave['ip']}:{slave['port']} - {slave['flags']}")

254

255

# Get other sentinels monitoring this master

256

sentinels_info = sentinel.sentinel_sentinels('mymaster')

257

for sent in sentinels_info:

258

print(f"Sentinel: {sent['ip']}:{sent['port']} - {sent['flags']}")

259

```

260

261

### Handling Failover Events

262

263

```python

264

import time

265

from redis.sentinel import Sentinel

266

from redis.exceptions import ConnectionError, ResponseError

267

268

sentinels = [('localhost', 26379), ('localhost', 26380), ('localhost', 26381)]

269

sentinel = Sentinel(sentinels, socket_timeout=0.1)

270

271

# Get master with automatic failover

272

master = sentinel.master_for('mymaster', socket_timeout=0.1)

273

274

def robust_operation():

275

"""Perform Redis operations with failover handling"""

276

max_retries = 3

277

retry_count = 0

278

279

while retry_count < max_retries:

280

try:

281

# Try to perform operation

282

master.set('test_key', f'value_{int(time.time())}')

283

value = master.get('test_key')

284

print(f"Operation successful: {value}")

285

return

286

287

except ConnectionError as e:

288

retry_count += 1

289

print(f"Connection error (attempt {retry_count}): {e}")

290

291

if retry_count < max_retries:

292

print("Waiting for failover...")

293

time.sleep(2) # Wait for Sentinel failover

294

295

# Get new master connection after failover

296

master = sentinel.master_for('mymaster', socket_timeout=0.1)

297

else:

298

print("Max retries exceeded")

299

raise

300

301

# Demonstrate robust operation

302

robust_operation()

303

```

304

305

### Sentinel Configuration Management

306

307

```python

308

from redis.sentinel import Sentinel

309

310

sentinels = [('localhost', 26379)]

311

sentinel = Sentinel(sentinels)

312

313

# Add a new master to monitor

314

sentinel.sentinel_monitor('newmaster', '127.0.0.1', 6380, 2)

315

316

# Configure master settings

317

sentinel.sentinel_set('newmaster', 'down-after-milliseconds', 5000)

318

sentinel.sentinel_set('newmaster', 'failover-timeout', 60000)

319

sentinel.sentinel_set('newmaster', 'parallel-syncs', 1)

320

321

# Check quorum for failover

322

can_failover = sentinel.sentinel_ckquorum('newmaster')

323

print(f"Can perform failover: {can_failover}")

324

325

# Force manual failover

326

if can_failover:

327

result = sentinel.sentinel_failover('newmaster')

328

print(f"Failover initiated: {result}")

329

330

# Remove master from monitoring

331

# sentinel.sentinel_remove('newmaster')

332

333

# Reset sentinel state

334

reset_count = sentinel.sentinel_reset('*')

335

print(f"Reset {reset_count} masters")

336

337

# Save configuration

338

sentinel.sentinel_flushconfig()

339

```

340

341

### Pub/Sub with Sentinel

342

343

```python

344

import time

345

from redis.sentinel import Sentinel

346

347

sentinels = [('localhost', 26379), ('localhost', 26380), ('localhost', 26381)]

348

sentinel = Sentinel(sentinels)

349

350

# Get master for publishing

351

master = sentinel.master_for('mymaster')

352

353

# Get slave for subscribing (optional - can use master)

354

slave = sentinel.slave_for('mymaster')

355

356

# Publisher function

357

def publish_messages():

358

for i in range(10):

359

master.publish('news', f'Breaking news {i}')

360

time.sleep(1)

361

362

# Subscriber function

363

def subscribe_messages():

364

pubsub = master.pubsub() # Use master for pub/sub reliability

365

pubsub.subscribe('news')

366

367

for message in pubsub.listen():

368

if message['type'] == 'message':

369

print(f"Received: {message['data']}")

370

371

# Use threading or asyncio to run both

372

import threading

373

374

publisher_thread = threading.Thread(target=publish_messages)

375

subscriber_thread = threading.Thread(target=subscribe_messages)

376

377

subscriber_thread.start()

378

time.sleep(0.5) # Small delay to ensure subscription

379

publisher_thread.start()

380

381

publisher_thread.join()

382

```

383

384

### Error Handling with Sentinel

385

386

```python

387

from redis.sentinel import Sentinel

388

from redis.exceptions import (

389

ConnectionError,

390

ResponseError,

391

MasterNotFoundError,

392

SlaveNotFoundError

393

)

394

395

def setup_sentinel_client():

396

sentinels = [('localhost', 26379), ('localhost', 26380), ('localhost', 26381)]

397

398

try:

399

sentinel = Sentinel(sentinels, socket_timeout=1.0)

400

401

# Test master discovery

402

master_addr = sentinel.discover_master('mymaster')

403

print(f"Master found at: {master_addr}")

404

405

# Get master client

406

master = sentinel.master_for('mymaster', socket_timeout=1.0)

407

408

# Test connection

409

master.ping()

410

print("Successfully connected to Redis master via Sentinel")

411

412

return sentinel, master

413

414

except MasterNotFoundError as e:

415

print(f"Master not found: {e}")

416

raise

417

except ConnectionError as e:

418

print(f"Cannot connect to Sentinel: {e}")

419

raise

420

except ResponseError as e:

421

print(f"Sentinel response error: {e}")

422

raise

423

424

# Use the setup function

425

try:

426

sentinel, master = setup_sentinel_client()

427

428

# Perform operations

429

master.set('health_check', 'ok')

430

status = master.get('health_check')

431

print(f"Health check: {status}")

432

433

except Exception as e:

434

print(f"Failed to setup Sentinel client: {e}")

435

```