From 639208eeb8a44622994f832bc2d45d06ab636bc8 Mon Sep 17 00:00:00 2001 From: Maxwell Brown Date: Thu, 11 Jul 2024 16:02:22 -0400 Subject: [PATCH] Render a more helpful error message in Effect.timeout (#3228) --- .changeset/famous-windows-poke.md | 5 +++++ packages/effect/src/internal/core.ts | 4 ++++ packages/effect/src/internal/effect/circular.ts | 2 +- packages/effect/test/Effect/timeout.test.ts | 15 +++++++++++++++ 4 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 .changeset/famous-windows-poke.md diff --git a/.changeset/famous-windows-poke.md b/.changeset/famous-windows-poke.md new file mode 100644 index 0000000000..f0a5b1605c --- /dev/null +++ b/.changeset/famous-windows-poke.md @@ -0,0 +1,5 @@ +--- +"effect": patch +--- + +Render a more helpful error message when timing out an effect diff --git a/packages/effect/src/internal/core.ts b/packages/effect/src/internal/core.ts index 2385a82524..f33a15c022 100644 --- a/packages/effect/src/internal/core.ts +++ b/packages/effect/src/internal/core.ts @@ -5,6 +5,7 @@ import * as Chunk from "../Chunk.js" import * as Context from "../Context.js" import type * as Deferred from "../Deferred.js" import type * as Differ from "../Differ.js" +import * as Duration from "../Duration.js" import type * as Effect from "../Effect.js" import * as Either from "../Either.js" import * as Equal from "../Equal.js" @@ -2297,6 +2298,9 @@ export const TimeoutExceptionTypeId: Cause.TimeoutExceptionTypeId = Symbol.for( export const TimeoutException = makeException({ [TimeoutExceptionTypeId]: TimeoutExceptionTypeId }, "TimeoutException") +/** @internal */ +export const timeoutExceptionFromDuration = (duration: Duration.DurationInput): Cause.TimeoutException => + new TimeoutException(`Operation timed out before the specified duration of '${Duration.format(duration)}' elapsed`) /** @internal */ export const isTimeoutException = (u: unknown): u is Cause.TimeoutException => hasProperty(u, TimeoutExceptionTypeId) diff --git a/packages/effect/src/internal/effect/circular.ts b/packages/effect/src/internal/effect/circular.ts index d98904a53b..6972d688c9 100644 --- a/packages/effect/src/internal/effect/circular.ts +++ b/packages/effect/src/internal/effect/circular.ts @@ -419,7 +419,7 @@ export const timeout = dual< ) => Effect.Effect >(2, (self, duration) => timeoutFail(self, { - onTimeout: () => new core.TimeoutException(), + onTimeout: () => core.timeoutExceptionFromDuration(duration), duration })) diff --git a/packages/effect/test/Effect/timeout.test.ts b/packages/effect/test/Effect/timeout.test.ts index 9ddf358d68..810f153169 100644 --- a/packages/effect/test/Effect/timeout.test.ts +++ b/packages/effect/test/Effect/timeout.test.ts @@ -10,6 +10,21 @@ import * as TestClock from "effect/TestClock" import { assert, describe } from "vitest" describe("Effect", () => { + it.effect("timeout produces a useful error message", () => + Effect.gen(function*() { + const duration = Duration.millis(1500) + const fiber = yield* Effect.never.pipe( + Effect.timeout(duration), + Effect.flip, + Effect.fork + ) + yield* TestClock.adjust(Duration.millis(2000)) + const result = yield* Fiber.join(fiber) + assert.include( + result.toString(), + "TimeoutException: Operation timed out before the specified duration of '1s 500ms' elapsed" + ) + })) it.live("timeout a long computation", () => Effect.gen(function*($) { const result = yield* $(