Skip to content

Add a Go-style defer() method for guaranteed cleanup #363

Closed

Description

@techmahedy

Area: Application lifecycle, HTTP, CLI, jobs, cache locks

Problem

Doppar already supports application terminating callbacks, but code that
acquires a temporary resource must either manage cleanup manually or know which
lifecycle hook to use. This makes local resource ownership harder to express
and makes cleanup ordering unclear.

Proposal

Add a defer() method that registers a callback for the end of the current
execution:

$lock = cache()->locked('report:' . $reportId, seconds: 30);

if (! $lock->get()) {
    throw new \RuntimeException('The report is already being generated.');
}

app()->defer(static function () use ($lock): void {
    $lock->release();
});

Doppar cache stores expose atomic locks through locked(). The returned
AtomicLock is acquired with get() (or block() when waiting is desired)
and released with release().

Callbacks execute in last-in-first-out order, matching Go's defer behavior.
They must run when the execution completes successfully or with an exception,
and must run before the execution context is discarded. The API should be
available through the application instance and an optional facade/helper:

app()->defer($callback);

Required semantics

  • A callback belongs only to the current execution context; it must not leak
    into the next request, job, or command in a long-lived worker.
  • Callbacks run in reverse registration order.
  • All callbacks are attempted even if one callback throws.
  • Cleanup exceptions are reported without replacing the original application
    exception; behavior for successful executions is documented.
  • Calling defer() outside an active execution either fails clearly or uses a
    documented application-lifetime fallback—this must not be implicit.
  • Nested execution contexts have independent callback stacks.

Acceptance criteria

  • Unit tests prove LIFO ordering.
  • Tests prove callbacks run after success and after an exception.
  • Tests prove one callback failure does not prevent later cleanup callbacks.
  • Persistent-worker tests prove callbacks and captured values do not leak.
  • HTTP, CLI, and job lifecycle adapters share the same implementation.
  • Documentation includes cache-lock, resource cleanup, temporary-file,
    tracing-span, and transaction examples.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Labels

featnew feature

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions