{"record":{"id":"61d5037578d2e9db","repo":"alibaba/canal","slug":"socket-has-interrupted","errorCode":null,"errorMessage":"socket has Interrupted !","messagePattern":"socket has Interrupted !","errorType":"exception","errorClass":"IOException","httpStatus":null,"severity":"error","filePath":"driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/socket/NettySocketChannel.java","lineNumber":175,"sourceCode":"            throw new IOException(\"write failed ! please checking !\");\r\n        }\r\n    }\r\n\r\n    public byte[] read(int readSize) throws IOException {\r\n        return read(readSize, 0);\r\n    }\r\n\r\n    public byte[] read(int readSize, int timeout) throws IOException {\r\n        int accumulatedWaitTime = 0;\r\n\r\n        // 若读取内容较长，则自动扩充超时时间，以初始缓存大小为基准计算倍数\r\n        if (timeout > 0 && readSize > DEFAULT_INIT_BUFFER_SIZE) {\r\n            timeout *= (readSize / DEFAULT_INIT_BUFFER_SIZE + 1);\r\n        }\r\n        do {\r\n            if (readSize > cache.readableBytes()) {\r\n                if (null == channel) {\r\n                    throw new IOException(\"socket has Interrupted !\");\r\n                }\r\n\r\n                if (timeout > 0) {\r\n                    accumulatedWaitTime += WAIT_PERIOD;\r\n                    if (accumulatedWaitTime > timeout) {\r\n                        StringBuilder sb = new StringBuilder(\"socket read timeout occured !\");\r\n                        sb.append(\" readSize = \").append(readSize);\r\n                        sb.append(\", readableBytes = \").append(cache.readableBytes());\r\n                        sb.append(\", timeout = \").append(timeout);\r\n                        throw new IOException(sb.toString());\r\n                    }\r\n                }\r\n\r\n                synchronized (this) {\r\n                    try {\r\n                        wait(WAIT_PERIOD);\r\n                    } catch (InterruptedException e) {\r\n                        throw new IOException(\"socket has Interrupted !\");\r","sourceCodeStart":157,"sourceCodeEnd":193,"githubUrl":"https://github.com/alibaba/canal/blob/87be50e87686a3e8af08c368d0e1ffd1f59eb04a/driver/src/main/java/com/alibaba/otter/canal/parse/driver/mysql/socket/NettySocketChannel.java#L157-L193","documentation":"Thrown by NettySocketChannel.read(int,int) when cache has fewer bytes than readSize and channel is null, i.e. the netty channel has been closed (close() nulls channel) while the reader is still waiting for data. Distinct from the timeout branch: here the channel disappeared, so waiting is pointless. The same message is reused for the InterruptedException-from-wait path.","triggerScenarios":"Reader thread in the wait-loop when close() sets channel=null; or the wait() is interrupted (InterruptedException caught) and re-thrown as this IOException. Happens during shutdown, reconnect, or when the reader thread is interrupted while blocked.","commonSituations":"Binlog parser thread blocked in read while an admin/error thread closes the channel; JVM shutdown interrupting reader threads; reconnect logic that closes the old channel before the reader exits its wait loop.","solutions":["Ensure the reader thread is stopped/interrupted cleanly before close() so it exits the wait loop.","Treat this IOException as a shutdown signal and break the read loop rather than propagating as a hard failure.","Coordinate close() and read() via a shared state flag (e.g. volatile boolean running).","Do not reuse the NettySocketChannel across reconnects."],"exampleFix":"// before\nbyte[] b = channel.read(len, timeoutMs); // throws 'socket has Interrupted !'\n\n// after\ntry {\n    byte[] b = channel.read(len, timeoutMs);\n} catch (IOException e) {\n    if (e.getMessage().contains(\"Interrupted\") || !running) {\n        // graceful shutdown of the reader\n        return;\n    }\n    throw e;\n}","handlingStrategy":"try-catch","validationCode":"// Reader loop: check a running flag and channel state before waiting\nif (!running || channel == null || !channel.isConnected()) { break; }","typeGuard":"public static boolean canReadNetty(NettySocketChannel nsc) {\n    return nsc != null && nsc.getChannel() != null;\n}","tryCatchPattern":"try {\n    byte[] b = nettyChannel.read(len, timeoutMs);\n} catch (java.io.IOException e) {\n    if (e.getMessage() != null && e.getMessage().contains(\"Interrupted\")) {\n        // graceful reader shutdown; exit loop\n        return;\n    }\n    throw e;\n}","preventionTips":["Signal a running flag false and stop reader threads before close().","Treat 'socket has Interrupted !' as a shutdown signal, not a hard failure.","Do not reuse NettySocketChannel instances across reconnects."],"tags":["network","netty","io","lifecycle","shutdown","concurrency"],"backgroundTag":null,"analyzedSha":"87be50e87686a3e8af08c368d0e1ffd1f59eb04a","analyzedAt":"2026-08-14T04:30:11.918Z","schemaVersion":2},"datasetVersion":"2026-08-14T05:17:29.042Z"}