or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

configuration.mderrors.mdhooks.mdhttp-methods.mdindex.mdinstances.mdresponses.mdretry.md
tile.json

retry.mddocs/

0

# Retry System

1

2

Configurable retry logic with exponential backoff, status code filtering, and Retry-After header support. Ky automatically retries failed requests based on configurable conditions.

3

4

## Capabilities

5

6

### Retry Configuration

7

8

Configure retry behavior with comprehensive options for different failure scenarios.

9

10

```typescript { .api }

11

interface RetryOptions {

12

/** Maximum number of retry attempts */

13

limit?: number;

14

/** HTTP methods allowed to retry */

15

methods?: string[];

16

/** HTTP status codes that trigger retry */

17

statusCodes?: number[];

18

/** Status codes that respect Retry-After header */

19

afterStatusCodes?: number[];

20

/** Maximum wait time for Retry-After header */

21

maxRetryAfter?: number;

22

/** Upper limit for retry delay */

23

backoffLimit?: number;

24

/** Custom delay calculation function */

25

delay?: (attemptCount: number) => number;

26

}

27

```

28

29

**Default Values:**

30

31

```typescript

32

const defaultRetryOptions = {

33

limit: 2,

34

methods: ['get', 'put', 'head', 'delete', 'options', 'trace'],

35

statusCodes: [408, 413, 429, 500, 502, 503, 504],

36

afterStatusCodes: [413, 429, 503],

37

maxRetryAfter: undefined, // Uses timeout value

38

backoffLimit: Infinity,

39

delay: (attemptCount) => 0.3 * (2 ** (attemptCount - 1)) * 1000

40

};

41

```

42

43

**Usage Examples:**

44

45

```typescript

46

import ky from "ky";

47

48

// Simple retry limit

49

const simpleRetry = await ky.get("https://api.example.com/unstable", {

50

retry: 5 // Retry up to 5 times with default settings

51

}).json();

52

53

// Custom retry configuration

54

const customRetry = await ky.get("https://api.example.com/data", {

55

retry: {

56

limit: 3,

57

methods: ["get", "post"],

58

statusCodes: [408, 429, 500, 502, 503, 504],

59

delay: (attemptCount) => Math.min(1000 * attemptCount, 5000)

60

}

61

}).json();

62

63

// Aggressive retry for critical operations

64

const criticalClient = ky.create({

65

retry: {

66

limit: 10,

67

methods: ["get", "post", "put", "patch", "delete"],

68

statusCodes: [408, 413, 429, 500, 502, 503, 504],

69

backoffLimit: 30000, // Max 30 second delay

70

delay: (attemptCount) => {

71

// Exponential backoff with jitter

72

const baseDelay = 1000 * (2 ** (attemptCount - 1));

73

const jitter = Math.random() * 0.1 * baseDelay;

74

return baseDelay + jitter;

75

}

76

}

77

});

78

```

79

80

### Retry-After Header Support

81

82

Automatically respect server-provided retry timing through HTTP headers.

83

84

**Usage Examples:**

85

86

```typescript

87

import ky from "ky";

88

89

// Respect Retry-After header for rate limiting

90

const rateLimitedClient = ky.create({

91

retry: {

92

limit: 5,

93

afterStatusCodes: [413, 429, 503], // Honor Retry-After for these statuses

94

maxRetryAfter: 60000 // Wait maximum 60 seconds

95

}

96

});

97

98

// The client will automatically wait for the time specified in:

99

// - Retry-After header (seconds or HTTP date)

100

// - RateLimit-Reset header (fallback)

101

// - X-RateLimit-Reset header (GitHub-style)

102

// - X-Rate-Limit-Reset header (Twitter-style)

103

104

const data = await rateLimitedClient.get("https://api.example.com/limited").json();

105

106

// Custom max retry delay

107

const customDelayClient = ky.create({

108

retry: {

109

afterStatusCodes: [429],

110

maxRetryAfter: 10000, // Never wait more than 10 seconds

111

}

112

});

113

```

114

115

### Method-Specific Retry Behavior

116

117

Configure retry behavior per HTTP method for different operation types.

118

119

**Usage Examples:**

120

121

```typescript

122

import ky from "ky";

123

124

// Safe methods only (idempotent operations)

125

const safeRetryClient = ky.create({

126

retry: {

127

limit: 5,

128

methods: ["get", "head", "options"], // Only safe methods

129

statusCodes: [408, 429, 500, 502, 503, 504]

130

}

131

});

132

133

// Include PUT and DELETE (idempotent)

134

const idempotentClient = ky.create({

135

retry: {

136

limit: 3,

137

methods: ["get", "put", "delete", "head"],

138

statusCodes: [408, 500, 502, 503, 504]

139

}

140

});

141

142

// Retry POST for specific use cases (be careful!)

143

const postRetryClient = ky.create({

144

retry: {

145

limit: 2,

146

methods: ["get", "post"], // Only if POST is idempotent

147

statusCodes: [408, 500, 502, 503, 504]

148

}

149

});

150

151

// Different retry strategies per method

152

const hybridClient = ky.create({

153

prefixUrl: "https://api.example.com"

154

});

155

156

// GET requests with aggressive retry

157

const getData = (endpoint: string) => hybridClient.get(endpoint, {

158

retry: { limit: 5, methods: ["get"] }

159

});

160

161

// POST requests with conservative retry

162

const postData = (endpoint: string, data: any) => hybridClient.post(endpoint, {

163

json: data,

164

retry: { limit: 1, methods: ["post"], statusCodes: [408, 500] }

165

});

166

```

167

168

### Status Code Filtering

169

170

Configure which HTTP status codes should trigger retry attempts.

171

172

**Usage Examples:**

173

174

```typescript

175

import ky from "ky";

176

177

// Default retriable status codes

178

const defaultClient = ky.create({

179

retry: {

180

statusCodes: [

181

408, // Request Timeout

182

413, // Payload Too Large (with Retry-After)

183

429, // Too Many Requests (with Retry-After)

184

500, // Internal Server Error

185

502, // Bad Gateway

186

503, // Service Unavailable (with Retry-After)

187

504 // Gateway Timeout

188

]

189

}

190

});

191

192

// Custom status codes for specific APIs

193

const customStatusClient = ky.create({

194

retry: {

195

statusCodes: [

196

408, 429, 500, 502, 503, 504, // Standard codes

197

520, 521, 522, 523, 524 // Cloudflare-specific codes

198

]

199

}

200

});

201

202

// Minimal retry for fast-fail scenarios

203

const fastFailClient = ky.create({

204

retry: {

205

limit: 1,

206

statusCodes: [500, 502, 503], // Only server errors

207

delay: () => 100 // Very short delay

208

}

209

});

210

211

// Never retry client errors (4xx)

212

const noClientErrorRetry = ky.create({

213

retry: {

214

statusCodes: [408, 500, 502, 503, 504], // Excludes 413, 429

215

afterStatusCodes: [] // No Retry-After respect

216

}

217

});

218

```

219

220

### Custom Delay Strategies

221

222

Implement custom delay calculations for different backoff strategies.

223

224

**Usage Examples:**

225

226

```typescript

227

import ky from "ky";

228

229

// Linear backoff

230

const linearClient = ky.create({

231

retry: {

232

delay: (attemptCount) => attemptCount * 1000 // 1s, 2s, 3s, 4s...

233

}

234

});

235

236

// Exponential backoff with jitter

237

const jitterClient = ky.create({

238

retry: {

239

delay: (attemptCount) => {

240

const baseDelay = 1000 * (2 ** (attemptCount - 1));

241

const jitter = Math.random() * 0.1 * baseDelay;

242

return baseDelay + jitter;

243

},

244

backoffLimit: 10000 // Cap at 10 seconds

245

}

246

});

247

248

// Fibonacci backoff

249

const fibonacciClient = ky.create({

250

retry: {

251

delay: (attemptCount) => {

252

const fibonacci = (n: number): number => {

253

if (n <= 1) return n;

254

return fibonacci(n - 1) + fibonacci(n - 2);

255

};

256

return fibonacci(attemptCount) * 1000;

257

}

258

}

259

});

260

261

// Adaptive delay based on response time

262

let lastResponseTime = 1000;

263

264

const adaptiveClient = ky.create({

265

retry: {

266

delay: (attemptCount) => {

267

// Increase delay based on server response time

268

const baseDelay = Math.max(lastResponseTime * 2, 1000);

269

return baseDelay * attemptCount;

270

}

271

},

272

hooks: {

273

afterResponse: [

274

(request, options, response) => {

275

// Track response time (simplified)

276

lastResponseTime = Date.now() - (request as any).startTime || 1000;

277

}

278

]

279

}

280

});

281

```

282

283

### Retry with Timeout Interaction

284

285

Understanding how retry interacts with timeout settings.

286

287

**Usage Examples:**

288

289

```typescript

290

import ky from "ky";

291

292

// Total timeout includes all retry attempts

293

const timeoutClient = ky.create({

294

timeout: 30000, // 30 seconds total (including retries)

295

retry: {

296

limit: 3,

297

delay: (attemptCount) => 2000 * attemptCount // 2s, 4s, 6s

298

}

299

});

300

301

// Per-attempt timeout

302

const perAttemptClient = ky.create({

303

timeout: 5000, // 5 seconds per attempt

304

retry: {

305

limit: 5,

306

delay: (attemptCount) => 1000 * attemptCount

307

}

308

});

309

310

// Fast timeout, many retries

311

const fastRetryClient = ky.create({

312

timeout: 3000, // Fail fast per attempt

313

retry: {

314

limit: 10, // But try many times

315

delay: (attemptCount) => Math.min(500 * attemptCount, 5000)

316

}

317

});

318

319

// No retry on timeout

320

const noTimeoutRetryClient = ky.create({

321

timeout: 10000,

322

retry: {

323

limit: 3,

324

// Timeouts are never retried automatically

325

statusCodes: [500, 502, 503, 504] // Excludes timeout scenarios

326

}

327

});

328

```

329

330

## Types

331

332

```typescript { .api }

333

interface RetryOptions {

334

limit?: number;

335

methods?: string[];

336

statusCodes?: number[];

337

afterStatusCodes?: number[];

338

maxRetryAfter?: number;

339

backoffLimit?: number;

340

delay?: (attemptCount: number) => number;

341

}

342

343

// Retry can be configured as number (limit only) or full options

344

type RetryConfiguration = RetryOptions | number;

345

```