Skip to content

Commit f5851e2

Browse files
authored
Fix SessionPool client leak on reconnection and query failures, and preserve server error messages
1 parent 54545a5 commit f5851e2

1 file changed

Lines changed: 36 additions & 9 deletions

File tree

src/Apache.IoTDB/SessionPool.cs

Lines changed: 36 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -157,9 +157,12 @@ protected internal SessionPool(List<string> nodeUrls, string username, string pa
157157
public async Task<TResult> ExecuteClientOperationAsync<TResult>(AsyncOperation<TResult> operation, string errMsg, bool retryOnFailure = true, bool putClientBack = true)
158158
{
159159
Client client = _clients.Take();
160+
bool shouldReturnClient = true;
161+
bool operationSucceeded = false;
160162
try
161163
{
162164
var resp = await operation(client);
165+
operationSucceeded = true;
163166
return resp;
164167
}
165168
catch (TException ex)
@@ -169,16 +172,25 @@ public async Task<TResult> ExecuteClientOperationAsync<TResult>(AsyncOperation<T
169172
try
170173
{
171174
client = await Reconnect(client);
172-
return await operation(client);
175+
var resp = await operation(client);
176+
operationSucceeded = true;
177+
return resp;
173178
}
174-
catch (TException retryEx)
179+
catch (Exception retryEx)
175180
{
176-
throw new TException(errMsg, retryEx);
181+
// Reconnection failed or retry operation failed
182+
// Client is closed by Reconnect, should not be returned to pool
183+
shouldReturnClient = false;
184+
// Preserve original error message from server
185+
string detailedMsg = $"{errMsg}. {retryEx.Message}";
186+
throw new TException(detailedMsg, retryEx);
177187
}
178188
}
179189
else
180190
{
181-
throw new TException(errMsg, ex);
191+
// Preserve original error message from server
192+
string detailedMsg = $"{errMsg}. {ex.Message}";
193+
throw new TException(detailedMsg, ex);
182194
}
183195
}
184196
catch (Exception ex)
@@ -188,21 +200,36 @@ public async Task<TResult> ExecuteClientOperationAsync<TResult>(AsyncOperation<T
188200
try
189201
{
190202
client = await Reconnect(client);
191-
return await operation(client);
203+
var resp = await operation(client);
204+
operationSucceeded = true;
205+
return resp;
192206
}
193-
catch (TException retryEx)
207+
catch (Exception retryEx)
194208
{
195-
throw new TException(errMsg, retryEx);
209+
// Reconnection failed or retry operation failed
210+
// Client is closed by Reconnect, should not be returned to pool
211+
shouldReturnClient = false;
212+
// Preserve original error message from server
213+
string detailedMsg = $"{errMsg}. {retryEx.Message}";
214+
throw new TException(detailedMsg, retryEx);
196215
}
197216
}
198217
else
199218
{
200-
throw new TException(errMsg, ex);
219+
// Preserve original error message from server
220+
string detailedMsg = $"{errMsg}. {ex.Message}";
221+
throw new TException(detailedMsg, ex);
201222
}
202223
}
203224
finally
204225
{
205-
if (putClientBack)
226+
// Return client to pool if:
227+
// 1. putClientBack is true (normal operations - client should always be returned), OR
228+
// 2. putClientBack is false (query operations) BUT operation failed, meaning SessionDataSet
229+
// wasn't created and won't manage the client
230+
// Do NOT return if reconnection failed (shouldReturnClient is false) because client was closed by Reconnect
231+
bool shouldReturnForQueryFailure = !putClientBack && !operationSucceeded;
232+
if (shouldReturnClient && (putClientBack || shouldReturnForQueryFailure))
206233
{
207234
_clients.Add(client);
208235
}

0 commit comments

Comments
 (0)