Skip to content

AdapterClient: adapter.readData timeout error kills the session instead of recovering #43

@jgeudens

Description

@jgeudens

Summary

When the adapter's ReadDataHandler fires its 5-second read timeout it sends a JSON-RPC error response:

{ "id": N, "error": { "code": -32000, "message": "Read timed out" } }

AdapterClient::onErrorReceived() has explicit non-fatal handling for only two methods (adapter.validateDataPoint and adapter.expressionHelp). Every other method — including adapter.readData — falls through to the fatal path:

// src/ProtocolAdapter/adapterclient.cpp — onErrorReceived()
_state = State::IDLE;
_pProcess->stop();
emit sessionError("Adapter error on adapter.readData: Read timed out");

This terminates the entire session. The user must restart the adapter from scratch for what is a completely routine Modbus communication event (device slow/unreachable for one cycle).

Expected behaviour

A readData error (timeout or "read already in progress") should be a per-read, recoverable failure. AdapterClient should:

  1. Not change state or kill the process.
  2. Emit a signal that lets the caller know this particular read failed (e.g. emit readDataResult with all-invalid entries, or a dedicated readDataError(QString) signal).
  3. Remain in ACTIVE state so subsequent requestReadData() calls continue to work.

Steps to reproduce

  1. Start a session against a Modbus device that does not respond within 5 seconds.
  2. Call requestReadData().
  3. The adapter times out → sends {"code":-32000,"message":"Read timed out"}.
  4. sessionError() fires and the entire adapter session tears down.

Relevant code

File Location
src/ProtocolAdapter/adapterclient.cpp onErrorReceived() — missing non-fatal branch for adapter.readData
src/ProtocolAdapter/adapterclient.h signals — consider adding readDataError(QString)
src/handlers/readdatahandler.cpp onReadTimeout() — emits -32000 after 5 s

Proposed fix

In onErrorReceived(), add a branch analogous to the validateDataPoint one:

if (method == QStringLiteral("adapter.readData") && _state == State::ACTIVE)
{
    // Non-fatal: emit empty/invalid result or a dedicated error signal
    emit readDataResult(ResultDoubleList()); // or a new readDataError signal
    return;
}

The exact signal shape (empty list vs. dedicated error signal) should be agreed before implementing.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions