Description
Describe the bug
Working on my project using ModbusClientTCPasync with syncRequest
I run into several problems, this problems caused memory leaks and restastarts under a heavy usage in 30mins or so.
Due to my own deadlines, I couldn't open proper issues here, and I tried to fixed by my own, now it's working with my fork after 10h, and more than 1M requests done.
Here is the list of problems I found and the solutions I applied, the solutions are dirty and for my only use case of eModbus, since are the works of debuging the codebase for 40h with the goal of making it work to reach my deadlines.
- When a
syncRequest
fails doesn't return until lost patience is met (1min), so I implemented anisConnected
method to handle the connection by hand and avoid making request to a disconnected client. 020187e - Disconnect doesn't clean properly the internal queues 020187e#diff-97e9b5de8eb31838da2befd02446dc1c5bf735f09e9ae051f205044c5aa38882R194-R205
waitSync
leakssynResponses
even when lostPatience is triggered or the request is successful (I don't know how), I solved cleaning the map at the end of waitSync (I am using maxInFlight1
) d0c9155ModbusClientTCPasync
gets in an invalid state when an error happens, and all the subsequent requests errors since the client can't connect again. I solved it by reading the state directly fromAsyncClient.state()
02bf261
Example code
My code base is extensive and I don't have to make a standalone code to make it work. So here are a few snippset to understand the configuration related to the client
void MasterBrick::asClient(TokenGenerator *generator)
{
_client = new ModbusClientTCPasync(brick->getIP(), 502);
_client->setMaxInflightRequests(1);
_client->setTimeout(500);
_client->setIdleTimeout(500);
_generator = generator;
}
template <typename... Args>
ModbusMessage MasterBrick::_doRequest(Args&&... args)
{
_client->connect();
int timeout = millis() + 500;
while (!_client->isConnected()) {
if (timeout > millis()) {
_client->disconnect(true);
delay(10);
continue;
}
LOG_E("brick=%d, request error: not connected\n", brick->address());
ModbusMessage response;
response.setError(brick->address(), 0, TIMEOUT);
return response;
}
LOG_D("brick=%d, making request\n", xPortGetCoreID(), brick->address());
auto start = millis();
auto response = _client->syncRequest(_generator->generate(), brick->address(), std::forward<Args>(args) ...);
Error err = response.getError();
if (err != SUCCESS) {
_stats.error();
ModbusError e(err);
int elpased = millis()-start;
LOG_E("brick=%d, elpased=%dms, request error: %02X - %s\n", brick->address(), elpased, (int)e, (const char *)e);
delay(10);
return response;
}
_stats.success(millis() - start);
return response;
}
Additional context
I just wanted to report this since maybe you found it helpful, I don't have much time now to contribute back, but at least I reported some possible bugs.