Summary
The current fix for #567/#569 still overloads LeaseContext.before_lease_hook with two different meanings:
beforeLease work has actually completed
- cleanup should not deadlock
That is safe for the original no-hook deadlock, but it is still wrong for exporters that have a hook_executor without a configured before_lease hook, and it weakens ordering guarantees when a real before_lease hook is present.
Problem
serve() currently starts run_before_lease_hook() whenever self.hook_executor exists, even if the config only defines after_lease:
serve() checks self.hook_executor
run_before_lease_hook() then discovers config.before_lease is None, reports LEASE_READY, and sets before_lease_hook in finally
At the same time, handle_lease() only takes its no-hook fast path when self.hook_executor is None, and its finally block force-sets before_lease_hook before calling _cleanup_after_lease().
That creates two bugs:
- after_lease-only exporters still run the background before-hook task even though there is no real
before_lease hook configured.
before_lease_hook no longer strictly means beforeLease completion, so _cleanup_after_lease() can stop waiting for real before-hook completion once the finally path force-sets it.
Why this matters
after_lease-only configuration
With an after_lease hook but no before_lease hook:
serve() still schedules run_before_lease_hook()
handle_lease() does not do its no-hook LEASE_READY path because hook_executor exists
- if the lease ends early, cleanup can run before the background task finishes
- the background task can later report
LEASE_READY after cleanup, potentially racing with the next lease
real before_lease configuration
When a real before_lease hook is configured and the lease ends while it is still running, handle_lease().finally can force-set before_lease_hook. _cleanup_after_lease() then stops waiting on the same event even though the real hook is still in progress.
Expected behavior
The exporter should key this behavior on whether a real before_lease hook is configured, not on whether hook_executor exists.
That means:
- only start
run_before_lease_hook() when config.before_lease is present
- only use the no-hook
LEASE_READY fast path when config.before_lease is absent
- only wait in
_cleanup_after_lease() for real before-hook completion when config.before_lease is present
- only use the
finally deadlock-escape set() for the no-before-hook path
Related
Summary
The current fix for #567/#569 still overloads
LeaseContext.before_lease_hookwith two different meanings:beforeLeasework has actually completedThat is safe for the original no-hook deadlock, but it is still wrong for exporters that have a
hook_executorwithout a configuredbefore_leasehook, and it weakens ordering guarantees when a realbefore_leasehook is present.Problem
serve()currently startsrun_before_lease_hook()wheneverself.hook_executorexists, even if the config only definesafter_lease:serve()checksself.hook_executorrun_before_lease_hook()then discoversconfig.before_lease is None, reportsLEASE_READY, and setsbefore_lease_hookinfinallyAt the same time,
handle_lease()only takes its no-hook fast path whenself.hook_executor is None, and itsfinallyblock force-setsbefore_lease_hookbefore calling_cleanup_after_lease().That creates two bugs:
before_leasehook configured.before_lease_hookno longer strictly means beforeLease completion, so_cleanup_after_lease()can stop waiting for real before-hook completion once thefinallypath force-sets it.Why this matters
after_lease-only configuration
With an
after_leasehook but nobefore_leasehook:serve()still schedulesrun_before_lease_hook()handle_lease()does not do its no-hookLEASE_READYpath becausehook_executorexistsLEASE_READYafter cleanup, potentially racing with the next leasereal before_lease configuration
When a real
before_leasehook is configured and the lease ends while it is still running,handle_lease().finallycan force-setbefore_lease_hook._cleanup_after_lease()then stops waiting on the same event even though the real hook is still in progress.Expected behavior
The exporter should key this behavior on whether a real
before_leasehook is configured, not on whetherhook_executorexists.That means:
run_before_lease_hook()whenconfig.before_leaseis presentLEASE_READYfast path whenconfig.before_leaseis absent_cleanup_after_lease()for real before-hook completion whenconfig.before_leaseis presentfinallydeadlock-escapeset()for the no-before-hook pathRelated