SIGPIPE signal in PGDac while connection reset (Linux)
Posted: Thu 20 Sep 2018 14:58
TLDR;
I am using PGDac with Delphi 10.2 to create simple Linux daemon. The communication with the DB is really simple, I just need to send few SQL queries/inserts and process returned rows.
Everything works fine until I try to restart the database server (PostgreSQL 10). The very first command after the server restart causes SIGPIPE signal and the whole application is terminated even though I do wrap all my PGDac calls in try ... except block.
I think that the problem is very similar to viewtopic.php?f=7&t=25540 .
Details:
I do have some wrapper objects in my code, but basically I have two PGDac objects:
When I try to do SQL query, the code works cca like this:
This works fine until I restart the server. After the server is restarted this happen:
1) the connection.connected property is still true
2) the ping raises the exception with message "terminating connection due to administrator command"
3) however the connection.connected property is still true.
4) If I try to disconnect, the code tries to write something into the now dead socket and the OS responds with SIGPIPE
5) SIGPIPE signal will effectively terminate the whole application even though I tried to handle it main thread
If I do not use ping, the problem is the same, only few lines later when I try to open the query.
I even tried to use fPGConnection.Options.LocalFailover := true; and handle the connection error. But unfortunately it is the same. PGDac calls my handler, I output something to the log without modifying the RetryMode, then PGDac tries to close the connection and resend the query. However again when disconnecting it tries to send some data to the now dead socket and the OS responds with SIGPIPE
I did manage to hotfix the problem with adding flag MSG_NOSIGNAL to send() function in CRVioTcp.pas (function TCRVioTcp.WriteNoWait, line 906):
With this hotfix OS does not generate SIGPIPE and the ping (or opening query) raises exception " Error on data writing to the connection:#015#012System error: 20.#015#012Socket Error Code: 32($20)". However the connected property is still true and I need to manually set it to false. And setting the connected property to false tries again to disconnect and so it tries to write the data to the still dead socket again and so it creates yet another exception (same message) but at least does set the connected to false. After this nested exception I am able to reconnect to the server and continue normally.
So my question is rather simple :-) How should I handle connection disconnects on Linux? The application is supposed to run for a long time (hopefully months in a single run) and should not die everytime the database server is restarted or unavailable....
I am using PGDac with Delphi 10.2 to create simple Linux daemon. The communication with the DB is really simple, I just need to send few SQL queries/inserts and process returned rows.
Everything works fine until I try to restart the database server (PostgreSQL 10). The very first command after the server restart causes SIGPIPE signal and the whole application is terminated even though I do wrap all my PGDac calls in try ... except block.
I think that the problem is very similar to viewtopic.php?f=7&t=25540 .
Details:
I do have some wrapper objects in my code, but basically I have two PGDac objects:
Code: Select all
fPGConnection: TPgConnection;
fquery:TPgQuery;
Code: Select all
try
if fPGConnection.Connected then fPGConnection.ping; //check if the connection is still alive
except
on e:Exception do
begin
log_msg(e.Message);
fPGConnection.Connected := false; //I would think that this is not needed
end;
end;
if not fPGConnection.Connected then Connect; //if not connected then call my function Connect that sets the connection params and opens the connection
if fPGConnection.Connected then //if connection is connected - try the SQL query
begin
fQuery.Connection := fPGConnection;
fQuery.SQL.Text := sql;
try
fQuery.Open;
except
on e:Exception do
begin
if e.message=SNotRows then begin end //ignore exception about query not returning rows
else raise(e);
end;
end;
end;
1) the connection.connected property is still true
2) the ping raises the exception with message "terminating connection due to administrator command"
3) however the connection.connected property is still true.
4) If I try to disconnect, the code tries to write something into the now dead socket and the OS responds with SIGPIPE
5) SIGPIPE signal will effectively terminate the whole application even though I tried to handle it main thread
If I do not use ping, the problem is the same, only few lines later when I try to open the query.
I even tried to use fPGConnection.Options.LocalFailover := true; and handle the connection error. But unfortunately it is the same. PGDac calls my handler, I output something to the log without modifying the RetryMode, then PGDac tries to close the connection and resend the query. However again when disconnecting it tries to send some data to the now dead socket and the OS responds with SIGPIPE
I did manage to hotfix the problem with adding flag MSG_NOSIGNAL to send() function in CRVioTcp.pas (function TCRVioTcp.WriteNoWait, line 906):
Code: Select all
Result := send(FSd, buffer[offset], count, MSG_NOSIGNAL);
So my question is rather simple :-) How should I handle connection disconnects on Linux? The application is supposed to run for a long time (hopefully months in a single run) and should not die everytime the database server is restarted or unavailable....