{"record":{"id":"cecda634cbbbc7f1","repo":"apache/pulsar","slug":"compaction-already-in-progress","errorCode":null,"errorMessage":"Compaction already in progress","messagePattern":"Compaction already in progress","errorType":"exception","errorClass":"org.apache.pulsar.broker.service.AlreadyRunningException","httpStatus":null,"severity":"warning","filePath":"pulsar-broker/src/main/java/org/apache/pulsar/broker/service/persistent/PersistentTopic.java","lineNumber":4925,"sourceCode":"                    return;\n                }\n\n                if (strategicCompactionMap.containsKey(topic)) {\n                    currentCompaction = brokerService.pulsar().getStrategicCompactor()\n                            .compact(topic, strategicCompactionMap.get(topic));\n                } else {\n                    currentCompaction = topicCompactionService.compact().thenApply(x -> null);\n                }\n            } finally {\n                lock.readLock().unlock();\n            }\n            currentCompaction.whenComplete((ignore, ex) -> {\n                if (ex != null) {\n                    log.warn().exception(ex).log(\"Compaction failure.\");\n                }\n            });\n        } else {\n            throw new AlreadyRunningException(\"Compaction already in progress\");\n        }\n    }\n\n    public synchronized LongRunningProcessStatus compactionStatus() {\n        final CompletableFuture<Long> current;\n        synchronized (this) {\n            current = currentCompaction;\n        }\n        if (!current.isDone()) {\n            return LongRunningProcessStatus.forStatus(LongRunningProcessStatus.Status.RUNNING);\n        } else {\n            try {\n                if (Objects.equals(current.join(), COMPACTION_NEVER_RUN)) {\n                    return LongRunningProcessStatus.forStatus(LongRunningProcessStatus.Status.NOT_RUN);\n                } else {\n                    return LongRunningProcessStatus.forStatus(LongRunningProcessStatus.Status.SUCCESS);\n                }\n            } catch (CancellationException | CompletionException e) {","sourceCodeStart":4907,"sourceCodeEnd":4943,"githubUrl":"https://github.com/apache/pulsar/blob/820761864ed8e2a7d2e52dd9763ad2ae117c1395/pulsar-broker/src/main/java/org/apache/pulsar/broker/service/persistent/PersistentTopic.java#L4907-L4943","documentation":"A topic can run only one compaction at a time; PersistentTopic tracks the in-flight compaction via a currentCompaction CompletableFuture. If triggerCompaction is called while a previous compaction has not finished, it throws AlreadyRunningException('Compaction already in progress'). This prevents two compaction runs from racing on the same ledger/topic.","triggerScenarios":"Calling admin topics().triggerCompaction() (REST or CLI) on a topic whose currentCompaction future is not yet done — e.g. invoking it twice in a row, or an automated job firing while a long-running compaction is still active.","commonSituations":"Scheduled compaction jobs overlapping with manually triggered compaction; very large topics where compaction takes hours; CI scripts retrying triggerCompaction without checking status; cron intervals shorter than compaction duration.","solutions":["Poll admin topics().compactionStatus() and only trigger when the status is NOT running (NOT_RUN/SUCCESS/ERROR)","Skip triggering on AlreadyRunningException and treat it as 'compaction already handled'","Reduce trigger frequency for scheduled compaction or add jitter/locking around the trigger call","Investigate why compaction is slow (huge backlog, resource limits) if it seems permanently stuck"],"exampleFix":"// before\nadmin.topics().triggerCompaction(topic); // throws if already running\n// after\nif (!LongRunningProcessStatus.Status.RUNNING.equals(admin.topics().compactionStatus(topic).status)) {\n    admin.topics().triggerCompaction(topic);\n}","handlingStrategy":"try-catch","validationCode":"LongRunningProcessStatus st = admin.topics().compactionStatus(topic);\nif (st.status == LongRunningProcessStatus.Status.RUNNING) {\n    return; // skip trigger\n}","typeGuard":"boolean canTriggerCompaction(LongRunningProcessStatus s) {\n    return s != null && s.status != LongRunningProcessStatus.Status.RUNNING;\n}","tryCatchPattern":"try {\n    admin.topics().triggerCompaction(topic);\n} catch (PulsarAdminException e) {\n    if (e.getCause() instanceof AlreadyRunningException) {\n        log.info(\"Compaction already running on {}\", topic);\n    } else throw e;\n}","preventionTips":["Poll compactionStatus() before every trigger","Make scheduled compaction jobs idempotent (skip if RUNNING)","Use intervals longer than worst-case compaction duration for large topics"],"tags":["pulsar","broker","compaction","long-running-process","conflict"],"backgroundTag":"compaction-already-running","analyzedSha":"820761864ed8e2a7d2e52dd9763ad2ae117c1395","analyzedAt":"2026-09-06T00:14:20.138Z","contentChangedAt":"2026-09-06T00:14:20.138Z","schemaVersion":2},"datasetVersion":"2026-09-14T00:17:10.932Z"}