[Bug]: TagBatch reuses a cached PlcReadRequest bound to a closed connection, so fetches fail after the first and never recover after a PLC restart
メンテナーはふだん 1 日以内に返信
@chrisdutz がすでに取り組んでいます。
2026年10月26日 から。
評価
- 難易度
- 3/5
- 見積もり時間
- 1〜2日
- 初心者へのやさしさ
- 72/100
- issue の種類
- バグ
- 明瞭さ
- 明確に書かれている
- 活発さ
- 活発
- 技術スタック
- java
調査の方向性
Read plc4j/tools/event-pump/src/main/java/org/apache/plc4x/java/tools/eventpump/TagBatch.java, focusing on fetchTags(), request caching, connection closing, and invalidateCache(). Reproduce with the issue's TagBatch example using DefaultPlcDriverManager, then repeat with PlcConnectionCache and restart the Modbus simulator. Done means later fetches use the current connection and continue after a PLC restart; add or update event-pump tests covering repeated fetches and recovery.
索引モデルが issue の本文から書いたものです。
説明
What happened?
TagBatch in plc4j-tools-event-pump builds its PlcReadRequest once and caches it (keyed only on the tag snapshot), but it obtains a connection from the configured PlcConnectionFactory on every fetch and closes that connection after the fetch. A PlcReadRequest is bound to the connection whose builder created it (DefaultPlcReadRequest keeps the PlcReader; execute() calls reader.read(this)), so the cached request keeps targeting the connection of the first fetch. Once that connection is closed, every later fetch fails without ever using the connection that was just opened for it.
Observed against a Modbus TCP simulator (oitc/modbus-server, Docker) with plc4j-tools-event-pump 1.0.0, plc4j-driver-modbus 1.0.0, TimerTrigger(100 ms), three tags (coil:1, holding-register:1:INT, holding-register:2:INT):
DefaultPlcDriverManageras connection factory (a new connection per fetch): fetch 1 succeeds, fetch 2 and every later attempt fail immediately withPlcRuntimeException: Failed to send request, root causeTransportException: Transport is closedatTcpTransportInstance.ensureOpen(TcpTransportInstance.java:319). Each attempt still logs "Modbus TCP connection established" for a connection that is never used. In 5 s: 1 fetch, 3 errors, back-off 1 s, 2 s, 4 s.PlcConnectionCacheas connection factory (one physical connection, a lease per fetch): 49 fetches in 5 s while the simulator is up. Afterdocker stop/docker startof the simulator the batch never recovers: 0 fetches in the following 65 s, every attempt fails withTransport is closed, and no "Connection refused" ever appears because the network is never touched. Even after the cache's idle validation detected the dead connection and opened a new one (at about +58 s), the next fetch failed again: the cached request still targets the old connection.
Cause, same on develop as in 1.0.0 (plc4j/tools/event-pump/src/main/java/org/apache/plc4x/java/tools/eventpump/TagBatch.java):
fetchTags()callsconnectionFactory.getConnection(connectionString)per fetch (line 516) and closes the connection in the completion handler (lines 604 and 621).- The read request is cached in
cachedReadRequest/cachedTagSnapshot(lines 122-123) and reused whenever the tag snapshot is unchanged (lines 529-541). invalidateCache()(lines 712-715) is private and is only called byaddTag(s)/removeTag(s)/clearTags, never on a fetch error or on a different connection.
Expected: a fetch executes its read request on the connection it obtained for that fetch, so a batch over DefaultPlcDriverManager keeps working and a batch over PlcConnectionCache recovers once the PLC is reachable again (the back-off then does its job instead of retrying a dead request forever).
Possible fixes, in order of simplicity: build the request on the connection of the current fetch (the PlcReadRequest.Builder cost is small compared to a network round trip); or cache the request per connection instance; or at least call invalidateCache() on every fetch error.
Workaround we verified: calling removeTag(name) + addTag(name, address) from TagBatchListener.onError forces a rebuild; with PlcConnectionCache the batch then recovers after a simulator restart (275 fetches in the 30 s after docker start, 3 errors in total). Side effect: the tag order in later responses changes.
Reproduction (JDK 21, plc4j-api, plc4j-tools-event-pump, plc4j-driver-modbus 1.0.0 on the classpath; docker run -d -p 127.0.0.1:5020:5020 oitc/modbus-server:latest):
TagBatch batch = TagBatch.builder()
.withBatchId("repro")
.withConnectionFactory(new DefaultPlcDriverManager())
.withConnectionString("modbus-tcp://127.0.0.1:5020")
.addTagAddress("c1", "coil:1")
.withTrigger(new TimerTrigger(100, TimeUnit.MILLISECONDS))
.withListener(new TagBatchListener() {
@Override
public void onTagsFetched(TagBatch b, PlcReadResponse r) {
System.out.println("fetched " + r.getResponseCode("c1"));
}
@Override
public void onError(TagBatch b, Throwable t) {
System.out.println("error " + t);
}
})
.build();
batch.start();
Thread.sleep(5000);
batch.close();
Output: one fetched OK, then only error ... Transport is closed lines. Replace the factory with PlcConnectionCache.getBuilder().withConnectionFactory(new DefaultPlcDriverManager()).build(), restart the simulator while the batch runs, and the error lines never stop.
Found while porting Apache Camel's camel-plc4x triggered consumer from plc4j-scraper to the event pump (CAMEL-25617).
Version
v1.0.0 (code unchanged on develop as of 2026-10-23)
Programming Languages
- plc4c
- plc4go
- plc4j
- plc4net
- plc4py
Protocols
- Modbus (used for the reproduction; the cause is protocol-independent)
- 主要言語
- Java
- スター
- 1.8k
- フォーク
- 512
- 平均マージ
- 2日 2時間
- マージ済み PR(30日)
- 34
環境構築
- Dockerfile または Docker Compose ファイルあり
- プルリクエストのテンプレートあり
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
apache/plc4x のほかの issue
-
Ethernet/IP java
難易度 1/5 1時間未満 初心者へのやさしさ 90/100
apache/plc4x#2733 · コメント 5 件 ·
メンテナーはふだん 1 日以内に返信
-
難易度 4/5 3〜5日 初心者へのやさしさ 52/100
メンテナーはふだん 1 日以内に返信
-
難易度 4/5 3〜5日 初心者へのやさしさ 45/100
メンテナーはふだん 1 日以内に返信
-
[Bug]: OPC-UA driver 1.0.0 fails against a certificate-less server even with security-policy=NONE (regression vs 0.13.1)対応中かも @splatch が 7 日前に担当しました。 オープン
メンテナーはふだん 1 日以内に返信
-
[Bug]: OPC UA UserNameIdentityToken sends length+password+nonce instead of the plain password when token security policy is None対応中かも @splatch が 27 日前に担当しました。 オープンOPC-UA
apache/plc4x#2791 · コメント 2 件 · 担当者 2 名 ·
メンテナーはふだん 1 日以内に返信
似ている issue
-
Component: Frontend Component: Web Component Type: Maintenance
難易度 2/5 1〜3時間 初心者へのやさしさ 76/100
it-at-m/refarch-templates#1944 ·
メンテナーはふだん 2 日以内に返信
-
priority: p2 type: bug
難易度 2/5 1〜3時間 初心者へのやさしさ 68/100
googleapis/java-genai#1372 ·
メンテナーはふだん 1 日以内に返信
-
難易度 2/5 1〜3時間 初心者へのやさしさ 60/100
-
GeoSeries scale and skew tests fail with pytest 9.2.0対応中かも @jiayuasu が今日担当しました。 オープン
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
メンテナーはふだん 1 日以内に返信
-
priority: medium Review effort [1-5]: 3 status: needs-triage type: bug
難易度 2/5 1〜3時間 初心者へのやさしさ 78/100
carlos-emr/carlos#5431 ·
メンテナーはふだん 1 日以内に返信