or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

application.mdconcurrency.mdindex.mdio.mdresources.mdtype-classes.md

resources.mddocs/

0

# Resource Management

1

2

Cats Effect provides comprehensive resource management through the Resource data type and bracket operations, ensuring proper cleanup of resources even in the presence of errors and cancellation.

3

4

## Capabilities

5

6

### Resource Data Type

7

8

The Resource data type provides safe resource handling with automatic cleanup.

9

10

```scala { .api }

11

/**

12

* Resource management data type with automatic cleanup

13

*/

14

abstract class Resource[F[_], A] {

15

/** Use the resource safely with automatic cleanup */

16

def use[B](f: A => F[B]): F[B]

17

18

/** Get the resource and its cleanup function */

19

def allocated: F[(A, F[Unit])]

20

21

/** Transform the resource value */

22

def map[B](f: A => B): Resource[F, B]

23

24

/** Chain another resource computation */

25

def flatMap[B](f: A => Resource[F, B]): Resource[F, B]

26

27

/** Replace the resource value with a constant */

28

def as[B](b: B): Resource[F, B]

29

30

/** Discard the resource value */

31

def void: Resource[F, Unit]

32

33

/** Apply an effect and return the original resource */

34

def evalTap[B](f: A => F[B]): Resource[F, A]

35

36

/** Combine with another resource */

37

def product[B](that: Resource[F, B]): Resource[F, (A, B)]

38

39

/** Map over both resources in a product */

40

def map2[B, C](that: Resource[F, B])(f: (A, B) => C): Resource[F, C]

41

42

/** Combine resources in parallel */

43

def parProduct[B](that: Resource[F, B]): Resource[F, (A, B)]

44

45

/** Map over parallel resource combination */

46

def parMap2[B, C](that: Resource[F, B])(f: (A, B) => C): Resource[F, C]

47

}

48

```

49

50

### Resource Construction

51

52

Various ways to construct Resource instances.

53

54

```scala { .api }

55

object Resource {

56

/** Create a resource with explicit acquire and release */

57

def make[F[_], A](acquire: F[A])(release: A => F[Unit])(implicit F: Bracket[F, Throwable]): Resource[F, A]

58

59

/** Create a resource from an AutoCloseable */

60

def fromAutoCloseable[F[_], A <: AutoCloseable](fa: F[A])(implicit F: Sync[F]): Resource[F, A]

61

62

/** Create a resource from an AutoCloseable with custom close */

63

def fromAutoCloseableBlocking[F[_], A <: AutoCloseable](fa: F[A], blocker: Blocker)(implicit F: Sync[F], cs: ContextShift[F]): Resource[F, A]

64

65

/** Lift an effect into a resource (no cleanup needed) */

66

def liftF[F[_], A](fa: F[A])(implicit F: Applicative[F]): Resource[F, A]

67

68

/** Create a resource from a pure value */

69

def pure[F[_], A](a: A)(implicit F: Applicative[F]): Resource[F, A]

70

71

/** Create a resource that always fails */

72

def raiseError[F[_], A](e: Throwable)(implicit F: ApplicativeError[F, Throwable]): Resource[F, A]

73

74

/** Create an empty resource */

75

def unit[F[_]](implicit F: Applicative[F]): Resource[F, Unit]

76

77

/** Suspend resource construction */

78

def suspend[F[_], A](fa: F[Resource[F, A]])(implicit F: Sync[F]): Resource[F, A]

79

80

/** Create resource from a finalizer and value */

81

def apply[F[_], A](acquire: F[A], release: F[Unit])(implicit F: Bracket[F, Throwable]): Resource[F, A]

82

}

83

```

84

85

**Usage Examples:**

86

87

```scala

88

import cats.effect._

89

import java.io._

90

91

// File resource with automatic closing

92

def fileResource[F[_]: Sync](path: String): Resource[F, BufferedReader] =

93

Resource.fromAutoCloseable(

94

Sync[F].delay(new BufferedReader(new FileReader(path)))

95

)

96

97

// Database connection resource

98

def dbConnectionResource[F[_]: Sync]: Resource[F, Connection] =

99

Resource.make(

100

acquire = Sync[F].delay(DriverManager.getConnection(url, user, password))

101

)(

102

release = conn => Sync[F].delay(conn.close())

103

)

104

105

// HTTP client resource

106

def httpClientResource[F[_]: Sync]: Resource[F, HttpClient] =

107

Resource.make(

108

acquire = Sync[F].delay(HttpClient.newHttpClient())

109

)(

110

release = client => Sync[F].delay(client.close())

111

)

112

113

// Using resources

114

def readFileContent[F[_]: Sync](path: String): F[String] =

115

fileResource(path).use { reader =>

116

Sync[F].delay(reader.lines().collect(Collectors.joining("\n")))

117

}

118

```

119

120

### Resource Composition

121

122

Combining multiple resources safely.

123

124

```scala { .api }

125

/**

126

* Combining and sequencing resources

127

*/

128

object Resource {

129

/** Sequence a list of resources */

130

def sequence[F[_], A](resources: List[Resource[F, A]]): Resource[F, List[A]]

131

132

/** Traverse with resource construction */

133

def traverse[F[_], A, B](list: List[A])(f: A => Resource[F, B]): Resource[F, List[B]]

134

135

/** Combine two resources into a tuple */

136

def both[F[_], A, B](ra: Resource[F, A], rb: Resource[F, B]): Resource[F, (A, B)]

137

}

138

139

/** Resource instance operations */

140

abstract class Resource[F[_], A] {

141

/** Combine with another resource */

142

def zip[B](that: Resource[F, B]): Resource[F, (A, B)]

143

144

/** Combine with another resource, keeping only the first */

145

def zipLeft[B](that: Resource[F, B]): Resource[F, A]

146

147

/** Combine with another resource, keeping only the second */

148

def zipRight[B](that: Resource[F, B]): Resource[F, B]

149

}

150

```

151

152

**Usage Examples:**

153

154

```scala

155

// Multiple resource composition

156

def multiResourceExample[F[_]: Sync]: Resource[F, (Connection, HttpClient, BufferedReader)] =

157

for {

158

db <- dbConnectionResource[F]

159

client <- httpClientResource[F]

160

file <- fileResource[F]("config.txt")

161

} yield (db, client, file)

162

163

// Parallel resource acquisition

164

def parallelResources[F[_]: Concurrent]: Resource[F, (String, String)] =

165

(

166

Resource.liftF(fetchFromAPI[F]("endpoint1")),

167

Resource.liftF(fetchFromAPI[F]("endpoint2"))

168

).parMapN((a, b) => (a, b))

169

170

// Resource list processing

171

def processFiles[F[_]: Sync](paths: List[String]): F[List[String]] =

172

Resource.traverse(paths)(fileResource[F]).use { readers =>

173

readers.traverse(reader => Sync[F].delay(reader.readLine()))

174

}

175

```

176

177

### Bracket Operations

178

179

Lower-level bracket operations for custom resource management.

180

181

```scala { .api }

182

/**

183

* Bracket operations for resource management patterns

184

*/

185

trait Bracket[F[_], E] {

186

/** Basic bracket operation */

187

def bracket[A, B](acquire: F[A])(use: A => F[B])(release: A => F[Unit]): F[B]

188

189

/** Bracket with access to exit case */

190

def bracketCase[A, B](acquire: F[A])(use: A => F[B])(release: (A, ExitCase[E]) => F[Unit]): F[B]

191

192

/** Ensure a finalizer always runs */

193

def guarantee[A](fa: F[A])(finalizer: F[Unit]): F[A]

194

195

/** Guarantee with access to exit case */

196

def guaranteeCase[A](fa: F[A])(finalizer: ExitCase[E] => F[Unit]): F[A]

197

198

/** Make an effect uncancelable */

199

def uncancelable[A](fa: F[A]): F[A]

200

201

/** Ensure finalizer runs regardless of outcome */

202

def onCancel[A](fa: F[A])(finalizer: F[Unit]): F[A]

203

}

204

205

/**

206

* Exit cases for bracket operations

207

*/

208

sealed abstract class ExitCase[+E]

209

object ExitCase {

210

/** Successful completion */

211

case object Completed extends ExitCase[Nothing]

212

213

/** Failed with error */

214

case class Error[E](e: E) extends ExitCase[E]

215

216

/** Canceled before completion */

217

case object Canceled extends ExitCase[Nothing]

218

}

219

```

220

221

**Usage Examples:**

222

223

```scala

224

// Custom resource with bracket

225

def withCustomResource[F[_]: Bracket[*[_], Throwable], A](

226

use: CustomResource => F[A]

227

): F[A] =

228

Bracket[F, Throwable].bracket(

229

acquire = Sync[F].delay {

230

val resource = new CustomResource()

231

resource.initialize()

232

resource

233

}

234

)(

235

use = use

236

)(

237

release = resource => Sync[F].delay(resource.cleanup())

238

)

239

240

// Bracket with exit case handling

241

def bracketWithLogging[F[_]: Bracket[*[_], Throwable], A](

242

acquire: F[A]

243

)(use: A => F[Unit]): F[Unit] =

244

Bracket[F, Throwable].bracketCase(acquire)(use) { (resource, exitCase) =>

245

val logMessage = exitCase match {

246

case ExitCase.Completed => "Resource used successfully"

247

case ExitCase.Error(e) => s"Resource failed with: ${e.getMessage}"

248

case ExitCase.Canceled => "Resource usage was canceled"

249

}

250

Sync[F].delay(println(logMessage))

251

}

252

```

253

254

### Resource Pooling

255

256

Advanced patterns for resource pooling and lifecycle management.

257

258

```scala { .api }

259

/**

260

* Resource pooling utilities (typically custom implementation)

261

*/

262

trait ResourcePool[F[_], A] {

263

/** Take a resource from the pool */

264

def take: F[A]

265

266

/** Return a resource to the pool */

267

def put(resource: A): F[Unit]

268

269

/** Use a resource from the pool temporarily */

270

def use[B](f: A => F[B]): F[B]

271

272

/** Close the entire pool */

273

def close: F[Unit]

274

}

275

276

object ResourcePool {

277

/** Create a resource pool */

278

def create[F[_]: Concurrent, A](

279

size: Int,

280

createResource: F[A],

281

destroyResource: A => F[Unit]

282

): Resource[F, ResourcePool[F, A]]

283

}

284

```

285

286

**Usage Examples:**

287

288

```scala

289

// Connection pool implementation

290

def connectionPool[F[_]: Concurrent](

291

maxConnections: Int

292

): Resource[F, ResourcePool[F, Connection]] = {

293

294

def createConnection: F[Connection] =

295

Sync[F].delay(DriverManager.getConnection(url, user, password))

296

297

def closeConnection(conn: Connection): F[Unit] =

298

Sync[F].delay(conn.close())

299

300

ResourcePool.create(maxConnections, createConnection, closeConnection)

301

}

302

303

// Using the pool

304

def databaseOperation[F[_]: Concurrent]: F[ResultSet] =

305

connectionPool[F](10).use { pool =>

306

pool.use { connection =>

307

Sync[F].delay {

308

val stmt = connection.createStatement()

309

stmt.executeQuery("SELECT * FROM users")

310

}

311

}

312

}

313

```

314

315

## Types

316

317

```scala { .api }

318

/**

319

* Resource data type for safe resource management

320

*/

321

abstract class Resource[F[_], A]

322

323

/**

324

* Type class for bracket-based resource management

325

*/

326

trait Bracket[F[_], E] extends MonadError[F, E]

327

328

/**

329

* Exit case information for bracket operations

330

*/

331

sealed abstract class ExitCase[+E]

332

333

/**

334

* Resource pool abstraction

335

*/

336

trait ResourcePool[F[_], A]

337

338

/**

339

* Type aliases for common bracket patterns

340

*/

341

type BracketThrow[F[_]] = Bracket[F, Throwable]

342

```