pinpoint-apm/pinpoint · error · HBaseAccessException

Already closed

Error message

Already closed

What it means

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.

Source

Thrown at commons-hbase/src/main/java/com/navercorp/pinpoint/common/hbase/HbaseTemplate.java:175

            return ExecutorFactory.newFixedThreadPool(this.maxThreads, 1024 * 4, threadFactory);
        }
    }

    @Override
    public void destroy() throws Exception {

        if (isClose.compareAndSet(false, true)) {
            logger.info("HBaseTemplate.destroy()");
            final ExecutorService executor = this.executor;
            if (executor != null) {
                MoreExecutors.shutdownAndAwaitTermination(executor, Duration.ofSeconds(3));
            }
        }
    }

    private void assertAccessAvailable() {
        if (isClose.get()) {
            throw new HBaseAccessException("Already closed");
        }
    }

    @Override
    public <T> T find(TableName tableName, final Scan scan, final ResultsExtractor<T> action) {
        return execute(tableName, new TableCallback<>() {
            @Override
            public T doInTable(Table table) throws Throwable {
                try (ResultScanner scanner = table.getScanner(scan)) {
                    return action.extractData(scanner);
                }
            }
        });
    }

    @Override
    public <T> List<T> find(TableName tableName, final Scan scan, final RowMapper<T> action) {
        return find(tableName, scan, new RowMapperResultsExtractor<>(action));

View on GitHub (pinned to 744c3d3075)

Solutions

  1. Fix the lifecycle so the template is closed only after all dependent tasks finish (e.g. await executor shutdown before closing the context)
  2. Obtain a fresh HbaseTemplate (or reinitialize the closed one) instead of reusing the closed instance
  3. Catch HBaseAccessException and skip/queue the operation if the application is intentionally shutting down

Example fix

// before
results = closedTemplate.find(table, scan, extractor); // throws
// after
if (!closedTemplateIsClosed) { // check via try-catch on HBaseAccessException or keep your own state
    results = template.find(table, scan, extractor);
}
Defensive patterns

Strategy: try-catch

Validate before calling

// Track template lifecycle alongside usage
AtomicBoolean closed = new AtomicBoolean(false);
public <T> T safeFind(HbaseTemplate t, TableName table, Scan scan, ResultsExtractor<T> ex) {
    try {
        return t.find(table, scan, ex);
    } catch (HBaseAccessException e) {
        throw new IllegalStateException("Template closed before query", e);
    }
}

Try / catch

try {
    return hbaseTemplate.execute(tableName, tableCallback);
} catch (HBaseAccessException e) {
    log.warn("HbaseTemplate already closed, skipping operation: {}", e.getMessage());
    return null;
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Related errors


AI-assisted analysis of pinpoint-apm/pinpoint@744c3d3075 (2026-09-07). Data as JSON: /api/errors/f643507b7a29b7cb. Report an issue: GitHub.