Skip to content

Add a post-acquisition hook for the held lock-file descriptor #607

Description

@mmashwani

Severity: Enhancement (callers cannot initialize holder diagnostics after ownership without private descriptor access)

Summary

I would like filelock to provide a narrow post-acquisition hook that runs after
the native lock succeeds and before acquire() returns. The hook should receive
a borrowed descriptor while filelock retains ownership of its lifecycle.

This complements issue #592 and open PR #595. An opener callback controls
descriptor creation before ownership, but it cannot safely write PID,
generation, or diagnostic data that must belong only to the successful holder.

Environment

Reproduction

  1. Acquire a native FileLock.
  2. Attempt to initialize holder-only data through a public descriptor API or a
    callback that is guaranteed to run after the OS lock succeeds.
  3. Observe that acquire() returns a proxy or lock object, while the descriptor
    exists only in the private _context.lock_file_fd field.
  4. The opener callback proposed in PR ✨ feat(api): add optional lock-file opener hook #595 necessarily runs before native
    ownership and therefore cannot provide the missing post-lock timing.

Observed vs expected

Observed:

Writing holder-only diagnostics requires private _context access or replacing
private backend acquisition logic.

Expected:

Filelock owns acquisition timing and descriptor cleanup while a documented
hook may initialize holder data only after successful ownership.

Root cause (verified in source, 3.29.7)

FileLockContext.lock_file_fd
is the only stored native descriptor and is part of the private context.

AcquireReturnProxy
returns the lock, not a documented borrowed file object or descriptor.

Open PR #595 proposes a pre-lock FileOpener(path, flags, mode) -> fd
contract. It does not add a post-lock initialization point.

Suggested fix

Add a keyword-only callback such as on_acquired(fd) with these invariants:

  1. Invoke it only after the backend has acquired and validated the native lock.
  2. Treat the descriptor as borrowed. Filelock remains responsible for unlock
    and close.
  3. If the callback fails, release the just-acquired lock, close the descriptor,
    restore logical state, and propagate both errors if cleanup also fails.
  4. Invoke it once per physical acquisition, not once per nested counter step.
  5. Define sync and async behavior explicitly.
  6. Document that the descriptor is borrowed and must not be closed by the
    callback. If the callback may change file position or file contents, define
    those semantics explicitly.

A higher-level metadata-writer API is also suitable if maintainers prefer not
to expose a borrowed descriptor at all.

Verification

  • The hook runs after a successful OS lock and before acquire() returns.
  • A timed-out contender never runs the hook.
  • Nested acquisition does not rewrite holder data.
  • Hook failure leaves no live lock or descriptor.
  • Holder diagnostics remain intact when another process times out.
  • The feature composes with the opener callback proposed in PR ✨ feat(api): add optional lock-file opener hook #595.

I did not find an existing upstream issue or PR covering this exact post-lock
hook. Targeted searches for post acquisition descriptor hook and
on_acquired descriptor found no duplicate. A search for FileOpener found
PR #595, which is related but covers pre-lock descriptor creation rather than
post-lock holder initialization.

Current workaround

Read the private _context.lock_file_fd after acquisition or duplicate the
backend _acquire() method. The first relies on an internal field; the second
duplicates contention, cleanup, and platform behavior.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions