{"record":{"id":"1e091a67d66be41a","repo":"apache/druid","slug":"already-started-not-starting-again","errorCode":null,"errorMessage":"Already started, not starting again","messagePattern":"Already started, not starting again","errorType":"console","errorClass":null,"httpStatus":null,"severity":"info","filePath":"extensions-core/kafka-extraction-namespace/src/main/java/org/apache/druid/query/lookup/KafkaLookupExtractorFactory.java","lineNumber":157,"sourceCode":"    return kafkaProperties;\n  }\n\n  public long getConnectTimeout()\n  {\n    return connectTimeout;\n  }\n\n  public boolean isInjective()\n  {\n    return injective;\n  }\n\n  @Override\n  public boolean start()\n  {\n    synchronized (started) {\n      if (started.get()) {\n        LOG.warn(\"Already started, not starting again\");\n        return true;\n      }\n      if (executorService.isShutdown()) {\n        LOG.warn(\"Already shut down, not starting again\");\n        return false;\n      }\n      verifyKafkaProperties();\n\n      final String topic = getKafkaTopic();\n      LOG.debug(\"About to listen to topic [%s] with group.id [%s]\", topic, factoryId);\n      // this creates a ConcurrentMap\n      cacheHandler = cacheManager.createCache();\n      final Map<String, String> map = cacheHandler.getCache();\n      mapRef.set(map);\n\n\n      final CountDownLatch startingReads = new CountDownLatch(1);\n","sourceCodeStart":139,"sourceCodeEnd":175,"githubUrl":"https://github.com/apache/druid/blob/9b90983fd291f26935af934383ce360473179e4d/extensions-core/kafka-extraction-namespace/src/main/java/org/apache/druid/query/lookup/KafkaLookupExtractorFactory.java#L139-L175","documentation":"KafkaLookupExtractorFactory.start() is idempotent: if the lookup has already been started, it logs this warning and returns true without starting a second Kafka consumer. The same lock also refuses to restart after shutdown. Callers get true (already/now running) or false (cannot start).","triggerScenarios":"Calling start() twice on the same KafkaLookupExtractorFactory instance, e.g. lookup manager re-initialization races, or a test calling start() without stop() in between.","commonSituations":"Druid lookup configuration hot-reloads where the same factory object is started again, concurrent start attempts from multiple threads, or unit tests (testStartFailsOn*) that start once before exercising failure paths.","solutions":["No action needed — returning true means the lookup is running; rely on this idempotency","If you need a fresh consumer, call stop() then start(), noting that after shutdown() the factory can never restart (create a new factory instead)","Serialize start/stop calls if multiple threads race to start the same lookup","In tests, create a new factory instance per test case"],"exampleFix":"// before\nfactory.start();\nfactory.start(); // logs \"Already started, not starting again\"\n// after\nif (!factory.start()) {\n  throw new IllegalStateException(\"lookup failed to start\");\n} // or create a new KafkaLookupExtractorFactory for a fresh consumer","handlingStrategy":"type-guard","validationCode":"if (factory.isStarted()) { /* skip start() */ }","typeGuard":"static boolean safeStart(KafkaLookupExtractorFactory f) { return f.isStarted() || f.start(); }","tryCatchPattern":null,"preventionTips":["Check isStarted() before calling start() in custom code","Create a new factory instance after stop()/shutdown; factories cannot restart after shutdown","Serialize lookup lifecycle calls across threads"],"tags":["kafka","lookup","lifecycle","idempotency","druid"],"backgroundTag":"invalid-state-transition","analyzedSha":"9b90983fd291f26935af934383ce360473179e4d","analyzedAt":"2026-09-07T13:32:30.957Z","contentChangedAt":"2026-09-07T13:32:30.957Z","schemaVersion":2},"datasetVersion":"2026-09-14T11:17:12.474Z"}