{"record":{"id":"bbc3c10b3fd87782","repo":"alibaba/canal","slug":"has-startup-don-t-repeat-start","errorCode":null,"errorMessage":"{} has startup , don't repeat start","messagePattern":"(.+?) has startup , don't repeat start","errorType":"exception","errorClass":"CanalException","httpStatus":null,"severity":"error","filePath":"common/src/main/java/com/alibaba/otter/canal/common/AbstractCanalLifeCycle.java","lineNumber":19,"sourceCode":"package com.alibaba.otter.canal.common;\n\n/**\n * 基本实现\n * \n * @author jianghang 2012-7-12 上午10:11:07\n * @version 1.0.0\n */\npublic abstract class AbstractCanalLifeCycle implements CanalLifeCycle {\n\n    protected volatile boolean running = false; // 是否处于运行中\n\n    public boolean isStart() {\n        return running;\n    }\n\n    public void start() {\n        if (running) {\n            throw new CanalException(this.getClass().getName() + \" has startup , don't repeat start\");\n        }\n\n        running = true;\n    }\n\n    public void stop() {\n        if (!running) {\n            throw new CanalException(this.getClass().getName() + \" isn't start , please check\");\n        }\n\n        running = false;\n    }\n\n}\n","sourceCodeStart":1,"sourceCodeEnd":34,"githubUrl":"https://github.com/alibaba/canal/blob/87be50e87686a3e8af08c368d0e1ffd1f59eb04a/common/src/main/java/com/alibaba/otter/canal/common/AbstractCanalLifeCycle.java#L1-L34","documentation":"Thrown by AbstractCanalLifeCycle.start() when the component's `running` flag is already true. This is a double-start guard common to all Canal lifecycle components (CanalInstance, CanalServer, MetaManager, etc.). The volatile running flag ensures visibility across threads, and the non-atomic check-then-set means concurrent start() calls from different threads can both observe running==false, but the second setter is a no-op that does not throw — the throw only fires when running was already true before the call.","triggerScenarios":"Calling start() on a CanalLifeCycle component that is already running — e.g. calling canalServer.start() twice, or calling start() on a CanalInstance that was not stopped after a previous start.","commonSituations":"Lifecycle management code calls start() without first checking isStart(); a restart procedure fails to stop() before start(); multiple threads or initialization blocks both call start(); embedded canal usage where the application lifecycle and canal lifecycle are not synchronized.","solutions":["Check `component.isStart()` before calling `component.start()` to avoid double-start.","Ensure stop() is always called before re-starting a component in restart procedures.","Use a single lifecycle manager to control start/stop ordering and prevent concurrent lifecycle calls.","Add proper shutdown hooks so components are stopped before the JVM exits, preventing stale running state."],"exampleFix":"// before\nif (!canalInstance.isStart()) {\n    canalInstance.start();\n}\n// Note: this has a TOCTOU race in concurrent contexts.\n// For single-threaded lifecycle management:\ncanalInstance.start(); // safe if guaranteed not already started\n\n// idiomatic guard\nif (canalInstance.isStart()) {\n    canalInstance.stop();\n}\ncanalInstance.start();","handlingStrategy":"validation","validationCode":"// Guard double-start\nif (!component.isStart()) {\n    component.start();\n} else {\n    logger.info(\"{} is already started, skipping\", component.getClass().getSimpleName());\n}","typeGuard":"null","tryCatchPattern":"try {\n    component.start();\n} catch (CanalException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"don't repeat start\")) {\n        logger.info(\"Component already started: {}\", component.getClass().getName());\n    } else {\n        throw e;\n    }\n}","preventionTips":["Always check isStart() before calling start().","Centralize lifecycle management in a single coordinator to prevent concurrent start calls.","Ensure stop() is called in shutdown hooks before restart procedures."],"tags":["lifecycle","double-start","canal-common","state-management"],"backgroundTag":null,"analyzedSha":"87be50e87686a3e8af08c368d0e1ffd1f59eb04a","analyzedAt":"2026-08-14T04:30:11.918Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}