{"record":{"id":"f643507b7a29b7cb","repo":"pinpoint-apm/pinpoint","slug":"already-closed","errorCode":null,"errorMessage":"Already closed","messagePattern":"Already closed","errorType":"exception","errorClass":"HBaseAccessException","httpStatus":null,"severity":"error","filePath":"commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/HbaseTemplate.java","lineNumber":175,"sourceCode":"            return ExecutorFactory.newFixedThreadPool(this.maxThreads, 1024 * 4, threadFactory);\n        }\n    }\n\n    @Override\n    public void destroy() throws Exception {\n\n        if (isClose.compareAndSet(false, true)) {\n            logger.info(\"HBaseTemplate.destroy()\");\n            final ExecutorService executor = this.executor;\n            if (executor != null) {\n                MoreExecutors.shutdownAndAwaitTermination(executor, Duration.ofSeconds(3));\n            }\n        }\n    }\n\n    private void assertAccessAvailable() {\n        if (isClose.get()) {\n            throw new HBaseAccessException(\"Already closed\");\n        }\n    }\n\n    @Override\n    public <T> T find(TableName tableName, final Scan scan, final ResultsExtractor<T> action) {\n        return execute(tableName, new TableCallback<>() {\n            @Override\n            public T doInTable(Table table) throws Throwable {\n                try (ResultScanner scanner = table.getScanner(scan)) {\n                    return action.extractData(scanner);\n                }\n            }\n        });\n    }\n\n    @Override\n    public <T> List<T> find(TableName tableName, final Scan scan, final RowMapper<T> action) {\n        return find(tableName, scan, new RowMapperResultsExtractor<>(action));","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/pinpoint-apm/pinpoint/blob/744c3d3075e595656abb1ae331ad2c0e4c9eb996/commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/HbaseTemplate.java#L157-L193","documentation":"HbaseTemplate tracks its lifecycle with an AtomicBoolean isClose, set when close() is called. assertAccessAvailable(), invoked at the start of execute(), findParallel(), executeDistributedScan() and executeParallelDistributedScan(), throws HBaseAccessException('Already closed') if the template was closed, preventing reads/writes through a dead template.","triggerScenarios":"Calling execute(), find/findParallel, or executeDistributedScan on an HbaseTemplate instance after close() was invoked — typically after Spring context shutdown or explicit template close; reusing a cached template bean across application restarts.","commonSituations":"Async tasks or scheduled jobs holding a reference to the template that keeps running after the container closed it; a service singleton capturing HbaseTemplate before context refresh failure led to close; double-destroy of a lifecycle bean followed by more queries.","solutions":["Fix the lifecycle so the template is closed only after all dependent tasks finish (e.g. await executor shutdown before closing the context)","Obtain a fresh HbaseTemplate (or reinitialize the closed one) instead of reusing the closed instance","Catch HBaseAccessException and skip/queue the operation if the application is intentionally shutting down"],"exampleFix":"// before\nresults = closedTemplate.find(table, scan, extractor); // throws\n// after\nif (!closedTemplateIsClosed) { // check via try-catch on HBaseAccessException or keep your own state\n    results = template.find(table, scan, extractor);\n}","handlingStrategy":"try-catch","validationCode":"// Track template lifecycle alongside usage\nAtomicBoolean closed = new AtomicBoolean(false);\npublic <T> T safeFind(HbaseTemplate t, TableName table, Scan scan, ResultsExtractor<T> ex) {\n    try {\n        return t.find(table, scan, ex);\n    } catch (HBaseAccessException e) {\n        throw new IllegalStateException(\"Template closed before query\", e);\n    }\n}","typeGuard":null,"tryCatchPattern":"try {\n    return hbaseTemplate.execute(tableName, tableCallback);\n} catch (HBaseAccessException e) {\n    log.warn(\"HbaseTemplate already closed, skipping operation: {}\", e.getMessage());\n    return null;\n}","preventionTips":["Shut down schedulers/executors before the Spring context closes HbaseTemplate","Do not hold HbaseTemplate references in objects that outlive the context","Treat close() as terminal — recreate a new template bean instead of reusing a closed one","Centralize HBase access behind one component that checks lifecycle state before queries"],"tags":["hbase","lifecycle","closed-resource","template"],"backgroundTag":"connection-closed","analyzedSha":"744c3d3075e595656abb1ae331ad2c0e4c9eb996","analyzedAt":"2026-09-07T18:48:45.289Z","contentChangedAt":"2026-09-07T18:48:45.289Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}