{"record":{"id":"50e59d63e2736d19","repo":"apache/iceberg","slug":"interrupted-during-unlock-50e59d","errorCode":null,"errorMessage":"Interrupted during unlock","messagePattern":"Interrupted during unlock","errorType":"exception","errorClass":"UncheckedInterruptedException","httpStatus":null,"severity":"error","filePath":"flink/v2.2/flink/src/main/java/org/apache/iceberg/flink/maintenance/api/JdbcLockFactory.java","lineNumber":270,"sourceCode":"              conn -> {\n                try (PreparedStatement sql = conn.prepareStatement(DELETE_LOCK_SQL)) {\n                  sql.setString(1, type.key);\n                  sql.setString(2, lockId);\n                  sql.setString(3, instanceId);\n                  long count = sql.executeUpdate();\n                  LOG.info(\n                      \"Deleted {} lock with instanceId {} with row count {}\",\n                      this,\n                      instanceId,\n                      count);\n                }\n\n                return null;\n              });\n        }\n      } catch (InterruptedException e) {\n        Thread.currentThread().interrupt();\n        throw new UncheckedInterruptedException(e, \"Interrupted during unlock\");\n      } catch (SQLException e) {\n        // SQL exception happened when getting/updating lock information\n        throw new UncheckedSQLException(e, \"Failed to remove lock %s\", this);\n      }\n    }\n\n    @Override\n    public String toString() {\n      return MoreObjects.toStringHelper(this).add(\"type\", type).add(\"lockId\", lockId).toString();\n    }\n\n    @SuppressWarnings(\"checkstyle:NestedTryDepth\")\n    private String instanceId() {\n      try {\n        return pool.run(\n            conn -> {\n              try (PreparedStatement sql = conn.prepareStatement(GET_LOCK_SQL)) {\n                sql.setString(1, type.key);","sourceCodeStart":252,"sourceCodeEnd":288,"githubUrl":"https://github.com/apache/iceberg/blob/86d9c8fc543e7c56c9f624eb725f76c9baff9570/flink/v2.2/flink/src/main/java/org/apache/iceberg/flink/maintenance/api/JdbcLockFactory.java#L252-L288","documentation":"JdbcLock.unlock() removes this trigger's lock row/state from the JDBC lock table. If the thread is interrupted while executing the update/delete SQL, the interrupt flag is restored and an UncheckedInterruptedException is thrown. A stuck unlock can leave the lock held and block subsequent maintenance runs.","triggerScenarios":"Calling unlock() on a JdbcLock while the thread executing the get/update lock SQL is interrupted (job cancellation, shutdown hook, interrupt from a scheduler).","commonSituations":"Flink job restart or cancellation during maintenance commit; database hang causing the unlock SQL to block until an external interrupt; thread pool shutdown while maintenance is still finalizing.","solutions":["Inspect the wrapped cause and job logs to find who interrupted the thread; avoid cancelling during maintenance commits.","Verify the database is responsive so unlock SQL completes quickly instead of blocking until interrupted.","After restart, confirm the lock was actually released; clear stale lock rows in the lock table if orphaned.","Run unlock in shutdown paths that are not interrupted (or tolerate interruption and re-check lock state afterwards)."],"exampleFix":"// before\nexecutor.shutdownNow(); // interrupts thread holding the lock mid-unlock\n// after\nexecutor.shutdown();\nif (!executor.awaitTermination(60, TimeUnit.SECONDS)) {\n  executor.shutdownNow(); // interrupt only after unlock had a chance to finish\n}","handlingStrategy":"try-catch","validationCode":"if (Thread.currentThread().isInterrupted()) { /* do not start unlock */ }","typeGuard":null,"tryCatchPattern":"try { lock.unlock(); } catch (UncheckedInterruptedException e) { Thread.currentThread().interrupt(); /* schedule lock-state re-check */ }","preventionTips":["Use graceful executor shutdown (shutdown + awaitTermination) instead of shutdownNow during maintenance.","Keep unlock SQL short; ensure the DB is healthy before committing maintenance.","After any interruption, re-check and clean stale lock rows.","Run a single instance per lockId to avoid contention."],"tags":["jdbc","interrupted","lock","flink","unlock"],"backgroundTag":"thread-interrupted","analyzedSha":"86d9c8fc543e7c56c9f624eb725f76c9baff9570","analyzedAt":"2026-09-12T00:46:39.097Z","contentChangedAt":"2026-09-12T00:46:39.097Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}