or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

contrib.mddebugging.mdevents.mdexceptions.mdindex.mdload-shapes.mdtasksets.mduser-classes.mdwait-time.md

tasksets.mddocs/

0

# TaskSets and Task Management

1

2

TaskSets provide a way to organize related tasks and model complex user behavior patterns. Locust supports random task execution, sequential execution, and Markov chain-based probabilistic transitions between tasks.

3

4

## Capabilities

5

6

### TaskSet Base Class

7

8

The fundamental class for grouping and organizing tasks with shared state and lifecycle management.

9

10

```python { .api }

11

class TaskSet:

12

"""

13

Base class for organizing related tasks with shared state.

14

15

Attributes:

16

tasks (list | dict): Tasks to execute - functions, classes, or dict with weights

17

min_wait (float): Deprecated - minimum wait time

18

max_wait (float): Deprecated - maximum wait time

19

wait_function (callable): Function to determine wait time between tasks

20

user: Parent user instance

21

parent: Parent TaskSet or User

22

client: HTTP client from user (convenience access)

23

"""

24

25

def __init__(self, parent):

26

"""

27

Initialize TaskSet.

28

29

Args:

30

parent: Parent TaskSet or User instance

31

"""

32

33

def on_start(self):

34

"""Called when TaskSet starts executing."""

35

36

def on_stop(self):

37

"""Called when TaskSet stops executing."""

38

39

def run(self):

40

"""Main execution loop - runs tasks with wait times."""

41

42

def execute_task(self, task):

43

"""

44

Execute a single task.

45

46

Args:

47

task: Task function or class to execute

48

"""

49

50

def schedule_task(self):

51

"""Schedule the next task to be executed."""

52

53

def get_next_task(self):

54

"""

55

Get the next task to execute based on task weights.

56

57

Returns:

58

Task function or class to execute

59

"""

60

61

def wait_time(self):

62

"""

63

Calculate wait time before next task.

64

65

Returns:

66

float: Wait time in seconds

67

"""

68

69

def wait(self):

70

"""Wait before executing next task."""

71

72

def interrupt(self, reschedule=True):

73

"""

74

Interrupt current TaskSet execution.

75

76

Args:

77

reschedule (bool): Whether to reschedule the task

78

"""

79

80

@property

81

def user(self):

82

"""Get the root User instance."""

83

84

@property

85

def parent(self):

86

"""Get the parent TaskSet or User."""

87

88

@property

89

def client(self):

90

"""Get HTTP client from user (convenience property)."""

91

```

92

93

### SequentialTaskSet

94

95

TaskSet that executes tasks in the order they are defined rather than randomly selecting them.

96

97

```python { .api }

98

class SequentialTaskSet(TaskSet):

99

"""

100

TaskSet that executes tasks in sequential order.

101

102

Tasks are executed in the order they appear in the tasks list,

103

cycling back to the first task after the last one completes.

104

"""

105

106

# Inherits all TaskSet methods and attributes

107

# Overrides task selection to be sequential rather than random

108

```

109

110

### MarkovTaskSet

111

112

TaskSet that uses Markov chains for probabilistic task transitions, enabling complex user behavior modeling.

113

114

```python { .api }

115

class MarkovTaskSet(TaskSet):

116

"""

117

TaskSet using Markov chains for task transitions.

118

119

Tasks transition to other tasks based on probabilities defined

120

using @transition and @transitions decorators.

121

122

Attributes:

123

current (str): Current task/state name

124

abstract (bool): Mark as abstract class

125

"""

126

127

# Use with @transition and @transitions decorators to define state transitions

128

```

129

130

## Task Decorators

131

132

### task Decorator

133

134

Decorator to mark methods as tasks and specify their execution weight.

135

136

```python { .api }

137

def task(weight=1):

138

"""

139

Decorator to mark a method as a task.

140

141

Args:

142

weight (int): Relative weight for task selection (default: 1)

143

Higher weights make tasks more likely to be selected

144

145

Returns:

146

Decorated function marked as a task

147

148

Usage:

149

@task # weight=1

150

def simple_task(self): ...

151

152

@task(3) # weight=3 (3x more likely)

153

def important_task(self): ...

154

"""

155

```

156

157

### tag Decorator

158

159

Decorator to tag tasks for filtering during test execution.

160

161

```python { .api }

162

def tag(*tags):

163

"""

164

Decorator to tag tasks for filtering.

165

166

Args:

167

*tags (str): Variable number of tag strings

168

169

Returns:

170

Decorated function with tags

171

172

Usage:

173

@tag("api", "critical")

174

@task

175

def api_test(self): ...

176

177

@tag("slow")

178

@task

179

def slow_operation(self): ...

180

"""

181

```

182

183

## Markov Task Decorators

184

185

### transition Decorator

186

187

Decorator for defining single transitions in Markov TaskSets.

188

189

```python { .api }

190

def transition(func_name: str, weight: int = 1):

191

"""

192

Define a single transition from current task to target task.

193

194

Args:

195

func_name (str): Name of target task function

196

weight (int): Transition weight (default: 1)

197

198

Returns:

199

Decorated function with transition

200

201

Usage:

202

@transition("task_b", weight=2)

203

@task

204

def task_a(self): ...

205

"""

206

```

207

208

### transitions Decorator

209

210

Decorator for defining multiple transitions in Markov TaskSets.

211

212

```python { .api }

213

def transitions(weights):

214

"""

215

Define multiple transitions from current task to target tasks.

216

217

Args:

218

weights (dict | list): Dict of {func_name: weight} or

219

list of (func_name, weight) tuples or func_names

220

221

Returns:

222

Decorated function with transitions

223

224

Usage:

225

@transitions({"task_b": 2, "task_c": 1})

226

@task

227

def task_a(self): ...

228

229

@transitions([("task_b", 2), ("task_c", 1)])

230

@task

231

def task_a(self): ...

232

"""

233

```

234

235

## Usage Examples

236

237

### Basic TaskSet Example

238

239

```python

240

from locust import HttpUser, TaskSet, task, between

241

242

class UserBehavior(TaskSet):

243

def on_start(self):

244

# Setup for this TaskSet

245

self.login()

246

247

def login(self):

248

self.client.post("/login", json={

249

"username": "testuser",

250

"password": "secret"

251

})

252

253

@task(3)

254

def browse_pages(self):

255

pages = ["/", "/about", "/products", "/contact"]

256

page = random.choice(pages)

257

self.client.get(page)

258

259

@task(1)

260

def search(self):

261

query = random.choice(["python", "testing", "locust"])

262

self.client.get(f"/search?q={query}")

263

264

def on_stop(self):

265

# Cleanup for this TaskSet

266

self.client.post("/logout")

267

268

class WebsiteUser(HttpUser):

269

tasks = [UserBehavior]

270

wait_time = between(1, 3)

271

```

272

273

### Nested TaskSets Example

274

275

```python

276

from locust import HttpUser, TaskSet, task, between

277

278

class AdminBehavior(TaskSet):

279

weight = 1 # Less likely to be selected

280

281

@task

282

def manage_users(self):

283

self.client.get("/admin/users")

284

285

@task

286

def view_reports(self):

287

self.client.get("/admin/reports")

288

289

class ShoppingBehavior(TaskSet):

290

weight = 3 # More likely to be selected

291

292

@task(2)

293

def browse_products(self):

294

self.client.get("/products")

295

296

@task(1)

297

def add_to_cart(self):

298

product_id = random.randint(1, 100)

299

self.client.post(f"/cart/add/{product_id}")

300

301

class WebsiteUser(HttpUser):

302

tasks = [AdminBehavior, ShoppingBehavior]

303

wait_time = between(1, 5)

304

```

305

306

### SequentialTaskSet Example

307

308

```python

309

from locust import HttpUser, SequentialTaskSet, task, between

310

311

class OrderProcess(SequentialTaskSet):

312

"""Tasks execute in order: browse -> select -> checkout -> complete"""

313

314

@task

315

def browse_products(self):

316

self.client.get("/products")

317

318

@task

319

def select_product(self):

320

self.product_id = random.randint(1, 100)

321

self.client.get(f"/products/{self.product_id}")

322

323

@task

324

def add_to_cart(self):

325

self.client.post("/cart/add", json={

326

"product_id": self.product_id,

327

"quantity": 1

328

})

329

330

@task

331

def checkout(self):

332

self.client.get("/checkout")

333

self.client.post("/checkout", json={

334

"payment_method": "credit_card"

335

})

336

337

@task

338

def complete_order(self):

339

self.client.get("/order/complete")

340

# After completion, cycle back to browse_products

341

342

class ShoppingUser(HttpUser):

343

tasks = [OrderProcess]

344

wait_time = between(2, 5)

345

```

346

347

### MarkovTaskSet Example

348

349

```python

350

from locust import HttpUser, MarkovTaskSet, task, between

351

from locust.user.markov_taskset import transition, transitions

352

353

class UserJourney(MarkovTaskSet):

354

"""User behavior modeled as Markov chain with probabilistic transitions"""

355

356

@task

357

@transitions({"browse": 3, "search": 1, "logout": 1})

358

def homepage(self):

359

"""Entry point - users can browse, search, or logout"""

360

self.client.get("/")

361

362

@task

363

@transitions({"product_page": 2, "homepage": 1})

364

def browse(self):

365

"""Browse products - can go to specific product or back to homepage"""

366

self.client.get("/products")

367

368

@task

369

@transition("product_page", weight=3)

370

@transition("homepage", weight=1)

371

def search(self):

372

"""Search for products"""

373

query = random.choice(["laptop", "phone", "tablet"])

374

self.client.get(f"/search?q={query}")

375

376

@task

377

@transitions([("add_to_cart", 2), ("browse", 2), ("homepage", 1)])

378

def product_page(self):

379

"""View product details"""

380

product_id = random.randint(1, 100)

381

self.client.get(f"/products/{product_id}")

382

383

@task

384

@transitions({"checkout": 3, "browse": 1})

385

def add_to_cart(self):

386

"""Add item to cart"""

387

self.client.post("/cart/add", json={"product_id": 123})

388

389

@task

390

@transition("logout", weight=1)

391

def checkout(self):

392

"""Complete purchase"""

393

self.client.post("/checkout")

394

395

def logout(self):

396

"""End session - no @task decorator, only reached via transitions"""

397

self.client.post("/logout")

398

self.interrupt() # End this TaskSet

399

400

class MarkovUser(HttpUser):

401

tasks = [UserJourney]

402

wait_time = between(1, 3)

403

```

404

405

### TaskSet with Shared State

406

407

```python

408

from locust import HttpUser, TaskSet, task, between

409

410

class APITestSuite(TaskSet):

411

def on_start(self):

412

# Authenticate and store token

413

response = self.client.post("/auth/login", json={

414

"username": "api_user",

415

"password": "secret"

416

})

417

self.auth_token = response.json()["access_token"]

418

419

# Set headers for all subsequent requests

420

self.client.headers.update({

421

"Authorization": f"Bearer {self.auth_token}"

422

})

423

424

# Initialize shared test data

425

self.created_resources = []

426

427

@task(2)

428

def create_resource(self):

429

"""Create a new resource"""

430

resource_data = {

431

"name": f"test_resource_{random.randint(1000, 9999)}",

432

"description": "Test resource created by Locust"

433

}

434

435

response = self.client.post("/api/resources", json=resource_data)

436

if response.status_code == 201:

437

resource_id = response.json()["id"]

438

self.created_resources.append(resource_id)

439

440

@task(5)

441

def read_resource(self):

442

"""Read existing resources"""

443

if self.created_resources:

444

resource_id = random.choice(self.created_resources)

445

self.client.get(f"/api/resources/{resource_id}")

446

else:

447

# Fallback to reading first resource

448

self.client.get("/api/resources/1")

449

450

@task(1)

451

def update_resource(self):

452

"""Update an existing resource"""

453

if self.created_resources:

454

resource_id = random.choice(self.created_resources)

455

update_data = {

456

"description": f"Updated at {time.time()}"

457

}

458

self.client.put(f"/api/resources/{resource_id}", json=update_data)

459

460

@task(1)

461

def delete_resource(self):

462

"""Delete a resource"""

463

if self.created_resources:

464

resource_id = self.created_resources.pop()

465

self.client.delete(f"/api/resources/{resource_id}")

466

467

def on_stop(self):

468

# Cleanup remaining resources

469

for resource_id in self.created_resources:

470

self.client.delete(f"/api/resources/{resource_id}")

471

472

class APIUser(HttpUser):

473

tasks = [APITestSuite]

474

wait_time = between(0.5, 2)

475

```

476

477

## Types

478

479

```python { .api }

480

from typing import Union, List, Dict, Callable, Any, Optional

481

482

# Task definition types

483

TaskFunction = Callable[[], None]

484

TaskClass = type # TaskSet subclass

485

TaskWeight = int

486

TaskDict = Dict[Union[TaskFunction, TaskClass], TaskWeight]

487

TaskList = List[Union[TaskFunction, TaskClass, tuple]]

488

489

# TaskSet configuration

490

Tasks = Union[TaskList, TaskDict]

491

WaitFunction = Callable[[], float]

492

493

# Markov chain types

494

TransitionWeights = Dict[str, int]

495

TransitionList = List[Union[tuple[str, int], str]]

496

Transitions = Union[TransitionWeights, TransitionList]

497

```