EffectTalk
Back to Tour
resource-managementBeginner

Safely Bracket Resource Usage with `acquireRelease`

Use `Effect.acquireRelease` to guarantee a resource's cleanup logic runs, even if errors or interruptions occur.

Safely Bracket Resource Usage with acquireRelease

Guideline

Wrap the acquisition, usage, and release of a resource within an Effect.acquireRelease call. This ensures the resource's cleanup logic is executed, regardless of whether the usage logic succeeds, fails, or is interrupted.

Rationale

This pattern is the foundation of resource safety in Effect. It provides a composable and interruption-safe alternative to a standard try...finally block. The release effect is guaranteed to execute, preventing resource leaks which are common in complex asynchronous applications, especially those involving concurrency where tasks can be cancelled.

Good Example

import { Effect, Console } from "effect";

// A mock resource that needs to be managed
const getDbConnection = Effect.sync(() => ({ id: Math.random() })).pipe(
  Effect.tap(() => Effect.log("Connection Acquired"))
);

const closeDbConnection = (conn: {
  id: number;
}): Effect.Effect<void, never, never> =>
  Effect.log(`Connection ${conn.id} Released`);

// The program that uses the resource
const program = Effect.acquireRelease(
  getDbConnection, // 1. acquire
  (connection) => closeDbConnection(connection) // 2. cleanup
).pipe(
  Effect.tap((connection) =>
    Effect.log(`Using connection ${connection.id} to run query...`)
  )
);

Effect.runPromise(Effect.scoped(program));

/*
Output:
Connection Acquired
Using connection 0.12345... to run query...
Connection 0.12345... Released
*/

Explanation: By using Effect.acquireRelease, the closeDbConnection logic is guaranteed to run after the main logic completes. This creates a self-contained, leak-proof unit of work that can be safely composed into larger programs.

Anti-Pattern

Using a standard try...finally block with async/await. While it handles success and failure cases, it is not interruption-safe. If the fiber executing the Promise is interrupted by Effect's structured concurrency, the finally block is not guaranteed to run, leading to resource leaks.

// ANTI-PATTERN: Not interruption-safe
async function getUser() {
  const connection = await getDbConnectionPromise(); // acquire
  try {
    return await useConnectionPromise(connection); // use
  } finally {
    // This block may not run if the fiber is interrupted!
    await closeConnectionPromise(connection); // release
  }
}