{"record":{"id":"f2ee4730fdb5a50b","repo":"code4craft/webmagic","slug":"already-closed","errorCode":null,"errorMessage":"Already closed!","messagePattern":"Already closed!","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"error","filePath":"webmagic-selenium/src/main/java/us/codecraft/webmagic/downloader/selenium/WebDriverPool.java","lineNumber":223,"sourceCode":"\t\t\t\t\t// ChromeDriver e = new ChromeDriver();\n\t\t\t\t\t// WebDriver e = getWebDriver();\n\t\t\t\t\t// innerQueue.add(e);\n\t\t\t\t\t// webDriverList.add(e);\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n\t\treturn innerQueue.take();\n\t}\n\n\tpublic void returnToPool(WebDriver webDriver) {\n\t\tcheckRunning();\n\t\tinnerQueue.add(webDriver);\n\t}\n\n\tprotected void checkRunning() {\n\t\tif (!stat.compareAndSet(STAT_RUNNING, STAT_RUNNING)) {\n\t\t\tthrow new IllegalStateException(\"Already closed!\");\n\t\t}\n\t}\n\n\tpublic void closeAll() {\n\t\tboolean b = stat.compareAndSet(STAT_RUNNING, STAT_CLODED);\n\t\tif (!b) {\n\t\t\tthrow new IllegalStateException(\"Already closed!\");\n\t\t}\n\t\tfor (WebDriver webDriver : webDriverList) {\n\t\t\tlogger.info(\"Quit webDriver\" + webDriver);\n\t\t\twebDriver.quit();\n\t\t\twebDriver = null;\n\t\t}\n\t}\n\n}\n","sourceCodeStart":205,"sourceCodeEnd":240,"githubUrl":"https://github.com/code4craft/webmagic/blob/67816a19d68a4fec4657bf1336227e046e251df2/webmagic-selenium/src/main/java/us/codecraft/webmagic/downloader/selenium/WebDriverPool.java#L205-L240","documentation":"WebDriverPool.checkRunning() verifies the pool's atomic state is still STAT_RUNNING via compareAndSet(STAT_RUNNING, STAT_RUNNING). If the pool has been closed (closeAll() or shutdown) or was never properly running, it throws IllegalStateException \"Already closed!\". get() and returnToPool() both call this, so any pool usage after closing fails.","triggerScenarios":"Calling pool.get(...) or pool.returnToPool(driver) after pool.closeAll() (or quitAll/shutdown) has flipped the state to STAT_CLODED; double-closing and then reusing the pool; concurrent close while another thread borrows a driver.","commonSituations":"App shutdown hooks closing the pool while scheduled crawling tasks still run; accidentally calling closeAll() in a finally block per-request instead of at application end; sharing one pool instance across threads that race close vs. get.","solutions":["Don't call get()/returnToPool() after closeAll(); create a new WebDriverPool instance if drivers are needed again (the pool cannot be reopened).","Move closeAll() to the application's final shutdown hook only, not per-request code paths.","Guard usage with a lifecycle flag or synchronize pool access so close and borrow don't race.","Check for double-close in finally blocks (e.g. closeAll called in both a request handler and a shutdown hook)."],"exampleFix":"// before\ntry {\n    driver = pool.get(url);\n    ...\n} finally {\n    pool.closeAll(); // closes pool for everyone\n}\n// after\ndriver = pool.get(url);\n...\npool.returnToPool(driver); // closeAll() only at application shutdown","handlingStrategy":"try-catch","validationCode":"// pool state is internal; track lifecycle yourself\nif (poolClosed) throw new IllegalStateException(\"Pool already closed; create a new WebDriverPool\");","typeGuard":null,"tryCatchPattern":"try {\n    WebDriver driver = pool.get(url);\n} catch (IllegalStateException e) {\n    if (\"Already closed!\".equals(e.getMessage())) {\n        throw new IllegalStateException(\"WebDriverPool was closed; rebuild it or fix your shutdown ordering\", e);\n    }\n    throw e;\n}","preventionTips":["Call closeAll() only from a single application shutdown hook","Never close the pool inside per-request finally blocks","Synchronize pool access across threads that borrow and close","Treat WebDriverPool as single-use: create a new instance if drivers are needed after closing"],"tags":["java","selenium","concurrency","lifecycle"],"backgroundTag":"invalid-state-transition","analyzedSha":"67816a19d68a4fec4657bf1336227e046e251df2","analyzedAt":"2026-09-08T11:15:28.425Z","contentChangedAt":"2026-09-08T11:15:28.425Z","schemaVersion":2},"datasetVersion":"2026-09-16T04:17:20.429Z"}