{"record":{"id":"d232f80a53f49ab4","repo":"t8y2/dbx","slug":"interrupted-while-waiting-for-a-jdbc-workload-leas","errorCode":null,"errorMessage":"Interrupted while waiting for a JDBC workload lease","messagePattern":"Interrupted while waiting for a JDBC workload lease","errorType":"exception","errorClass":"SQLException","httpStatus":null,"severity":"warning","filePath":"agents/common/src/main/java/com/dbx/agent/JdbcConnectionPoolRegistry.java","lineNumber":661,"sourceCode":"                    retireAfterCheckoutFailure(deadline);\n                    throw AgentRpcError.resource(\"connect\", causalFailure == null ? error : causalFailure);\n                }\n                throw error;\n            }\n        }\n\n        private boolean acquirePermit(\n            Semaphore permits,\n            OperationDeadline deadline,\n            String exhaustedMessage\n        ) throws SQLException {\n            try {\n                if (permits.tryAcquire(deadline.remainingNanos(), TimeUnit.NANOSECONDS)) {\n                    return true;\n                }\n            } catch (InterruptedException error) {\n                Thread.currentThread().interrupt();\n                throw new SQLException(\"Interrupted while waiting for a JDBC workload lease\", error);\n            }\n            throw AgentRpcError.backpressure(\n                \"checkout\",\n                new SQLTransientConnectionException(exhaustedMessage)\n            );\n        }\n\n        private synchronized boolean markQuarantined() {\n            quarantinedLeases += 1;\n            return quarantinedLeases >= maxQuarantinedOperations;\n        }\n\n        private void release(Connection connection, boolean evict, boolean workloadPermit, boolean quarantined) {\n            try {\n                connectionReleaseExecutor.release(\n                    dataSource,\n                    connection,\n                    evict,","sourceCodeStart":643,"sourceCodeEnd":679,"githubUrl":"https://github.com/t8y2/dbx/blob/c0390bff16418b651f4728520d99adf8ce48829a/agents/common/src/main/java/com/dbx/agent/JdbcConnectionPoolRegistry.java#L643-L679","documentation":"Thrown when the thread waiting on a Semaphore permit for a JDBC workload lease (or pool lease) is interrupted via Thread.interrupt(). The library restores the interrupt flag and rethrows as a SQLException with the interruption as cause. It signals the caller's own cancellation, not a pool fault.","triggerScenarios":"A caller of pool.checkout()/lease acquisition is blocked in acquirePermit's permits.tryAcquire(deadline) because all workload/lease permits are held, and another thread interrupts the blocked thread (e.g. executor.shutdownNow(), task cancellation, shutdown hooks).","commonSituations":"Application shutdown while connections are saturated; cancelling a future/request whose thread is queued waiting for a lease; thread pools being torn down with shutdownNow during a burst of concurrent checkouts.","solutions":["Let the application shutdown/cancellation proceed: catch SQLException, check the cause is InterruptedException, and treat it as cancelled work","Restore and honor the interrupt flag (the library already calls Thread.currentThread().interrupt()) so outer layers also cancel","Reduce checkout contention (shorter connection hold times, larger pool limits) so threads rarely block waiting for permits","If interruption is unexpected, audit which code path calls interrupt()/shutdownNow() on the worker thread"],"exampleFix":"// before\nLease lease = pool.checkout();\n// after\ntry {\n    Lease lease = pool.checkout();\n} catch (SQLException e) {\n    if (e.getCause() instanceof InterruptedException) {\n        Thread.currentThread().interrupt(); // already set by library; treat as cancellation\n        throw new CancellationException(\"checkout interrupted\");\n    }\n    throw e;\n}","handlingStrategy":"try-catch","validationCode":"if (Thread.currentThread().isInterrupted()) { throw new CancellationException(\"already interrupted; skip checkout\"); }","typeGuard":"static boolean isInterruption(SQLException e) {\n    Throwable c = e;\n    while (c != null) { if (c instanceof InterruptedException) return true; c = c.getCause(); }\n    return false;\n}","tryCatchPattern":"try {\n    lease = pool.checkout();\n} catch (SQLException e) {\n    if (isInterruption(e)) {\n        Thread.currentThread().interrupt();\n        throw new CancellationException(e);\n    }\n    throw e;\n}","preventionTips":["Do not call interrupt()/shutdownNow() on threads blocked in checkout; use pool drain/timeout APIs","Check Thread.interrupted() status before starting long checkout waits","Keep workload permits sized to actual concurrency so threads rarely block","Design shutdown to first stop submitting new checkouts, then await in-flight ones"],"tags":["jdbc","interruption","cancellation","concurrency"],"backgroundTag":"thread-interrupted","analyzedSha":"c0390bff16418b651f4728520d99adf8ce48829a","analyzedAt":"2026-09-05T23:05:10.900Z","contentChangedAt":"2026-09-05T23:05:10.900Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}