feat(daemon): keep a caller-owned lease through session close with retainOnClose - #3208
Conversation
…ose on lease reuse
97ade82 to
351ba42
Compare
351ba42 to
918e01b
Compare
|
Thanks for the PR. I found no blocking problem in the code at 918e01b. Default One piece of evidence is still missing. The PR body describes live Limrun iOS/Android runs (closeApp then open, a failing file then the next one, and the lease ending after a daemon stop), but there is no transcript. Could you paste the command output that shows the provider device still held after closeApp and released after the daemon stop? Simplicity question: declaring retention on the lease at allocation looks like the right owner. But Not blocking, take or leave these:
CI is green at this head, with 16 checks and none failing, and there are no conflicts. The PR is still a draft. Next step: the live transcript and an answer to the simplicity question. |
Session teardown no longer releases its own lease in beforeDelete. finalizeDaemonLeases releases every lease still active after teardown, held by a session or retained through close, with one bounded release path. It now runs in the shutdown diagnostics scope, so its timeout and failure warnings reach daemon.log; the per-session variant emitted them outside any scope, where they were dropped.
Idle reap ignored leases, so a retainOnClose lease no session held was released when the daemon reaped itself after five minutes, even with a longer ttlMs. A reap that finds an unexpired lease now waits another idle window; the check also expires leases past their window, so an abandoned lease still ends.
…ease's own client The client lease now carries retainOnClose, so a caller can tell whether the daemon honored it. Only an allocation from the lease's own client turns it on for a reused run lease. A close that keeps a retained lease emits session_lease_released with released: false, retained: true. ADR 0007 and the client API docs cover the idle-reap and expiry behavior.
Resolve teardownDaemonSessionForShutdown on main's SessionRef form without the per-session lease hook, wire hasActiveLeases beside the inFlightRequests set, keep both lifecycle-shutdown test suites, and move the retainOnClose close test to SessionStore.publish.
|
Finished the review items at 75c12eb, as commits on top of yours plus a merge of main. The new commits conflicted with main in
Live run: Limrun iOS and Android, retain and defaultDecisions for you:
Left open from the independent review (minor): no test pins the daemon's Gate: everything passes except one |
|
Reviewed at 75c12eb: the code looks good. A retainOnClose lease now survives session close, shutdown has one bounded release path, and the Limrun transcript above closes the earlier evidence gap. Checks pass and there are no conflicts. One decision for you: Not blocking: the removed |
DaemonRequestMeta and toLeaseDaemonRequest now carry both the retainOnClose fields from #3208 and providerCredentialFingerprint; their acks keep both rationales and the digest of the merged declarations.
|
On the open idle-reap question: this merged with every lease counting as activity. I chose to count only |
…rovider credentials (#3207) * fix(providers): refuse lease allocation when the daemon holds other provider credentials A local daemon keeps the environment it started with, while connect checks the shell's. A stale daemon could act on old credentials, for example creating a billed Limrun instance for an attach-mode shell. On a local lease_allocate the CLI now sends a versioned hash of the values each provider's own reader uses (Limrun, BrowserStack), over the socket and local HTTP; the daemon compares it with the hash of its startup environment and refuses with INVALID_ARGS, reason provider-credentials-changed, and a hint naming its state dir. No hash is sent from a shell without credentials or to remote, proxy, or cloud daemons; a daemon with an HTTP auth hook treats every caller as remote. AWS Device Farm is excluded. * fix(providers): keep the connect verification error shape; scrub the HTTP auth hook in tests verifyBrowserStack reads credentials through the shared reader again but keeps its COMMAND_FAILED 'profile missed' error and reconnect hint. The hermetic test setup now also clears AGENT_DEVICE_HTTP_AUTH_HOOK and _EXPORT, so a host with a hook configured cannot turn a local daemon test into a remote one. * chore(gates): record the combined lease wire digests after #3208 DaemonRequestMeta and toLeaseDaemonRequest now carry both the retainOnClose fields from #3208 and providerCredentialFingerprint; their acks keep both rationales and the digest of the merged declarations.
Summary
Session
closealways releases the session's lease. That has been the rule since #890, so a failed close can't strand a lease, and the CLI proxy flow relies on it to free devices. tester-army/e2e later started allocating leases itself and releasing them at run end (tester-army/e2e#416). It also closes sessions mid-run, ondevice.closeApp()and when it replaces a worker after a failing test file. Every later command failsUNAUTHORIZED: Lease is not active, and a provider-created Limrun instance gets deleted.This adds an opt-in
retainOnClosetoleases.allocate. That lease survivescloseand ends throughleases.release, expiry, or daemon shutdown, which now also releases leases no session holds. The default is unchanged, and an older daemon ignores the field.22 files. Fixing this in e2e would cost it a fresh session after failures and leave
closeAppbroken. tester-army/e2e#792 covers local claims, unchanged here.Validation
Tested commit
918e01b; CI pending on this head.pnpm check:affected --run: 4803 tests pass. Each new test fails under its mutation.retainOnClose:closeAppthenopen, a failing file then the next, and a 75 s idle pass. Without the flag, it fails aftercloseApp.readyafterclose,terminatedafterdaemon stop.