Fixed embeddings generation errors not propagating to response model in a user-friendly way, Fixed non-awaited SQL actions, Fixed connection pool filling up, fixed newly created searchdomain not found

This commit is contained in:
2026-02-19 03:00:46 +01:00
parent cda8c61429
commit 820ecbc83b
6 changed files with 31 additions and 22 deletions

View File

@@ -109,10 +109,19 @@ public class AIProvider
{
JObject responseContentJson = JObject.Parse(responseContent);
List<JToken>? responseContentTokens = [.. responseContentJson.SelectTokens(embeddingsJsonPath)];
if (responseContentTokens is null)
if (responseContentTokens is null || responseContentTokens.Count == 0)
{
_logger.LogError("Unable to select tokens using JSONPath {embeddingsJsonPath} for string: {responseContent}.", [embeddingsJsonPath, responseContent]);
throw new JSONPathSelectionException(embeddingsJsonPath, responseContent);
if (responseContentJson.TryGetValue("error", out JToken? errorMessageJson) && errorMessageJson is not null)
{
string errorMessage = errorMessageJson.Value<string>() ?? "";
_logger.LogError("Unable to retrieve embeddings due to error: {errorMessage}", [errorMessage]);
throw new Exception($"Unable to retrieve embeddings due to error: {errorMessage}");
} else
{
_logger.LogError("Unable to select tokens using JSONPath {embeddingsJsonPath} for string: {responseContent}.", [embeddingsJsonPath, responseContent]);
throw new JSONPathSelectionException(embeddingsJsonPath, responseContent);
}
}
return [.. responseContentTokens.Select(token => token.ToObject<float[]>() ?? throw new Exception("Unable to cast embeddings response to float[]"))];
}

View File

@@ -109,7 +109,7 @@ public class SearchdomainController : ControllerBase
/// <param name="newName">Updated name of the searchdomain</param>
/// <param name="settings">Updated settings of searchdomain</param>
[HttpPut]
public ActionResult<SearchdomainUpdateResults> Update([Required]string searchdomain, string newName, [FromBody]SearchdomainSettings? settings)
public async Task<ActionResult<SearchdomainUpdateResults>> Update([Required]string searchdomain, string newName, [FromBody]SearchdomainSettings? settings)
{
(Searchdomain? searchdomain_, int? httpStatusCode, string? message) = SearchdomainHelper.TryGetSearchdomain(_domainManager, searchdomain, _logger);
if (searchdomain_ is null || httpStatusCode is not null) return StatusCode(httpStatusCode ?? 500, new SearchdomainUpdateResults(){Success = false, Message = message});
@@ -120,7 +120,7 @@ public class SearchdomainController : ControllerBase
{"name", newName},
{"id", searchdomain_.id}
};
searchdomain_.helper.ExecuteSQLNonQuery("UPDATE searchdomain set name = @name WHERE id = @id", parameters);
await searchdomain_.helper.ExecuteSQLNonQuery("UPDATE searchdomain set name = @name WHERE id = @id", parameters);
} else
{
Dictionary<string, dynamic> parameters = new()
@@ -129,7 +129,7 @@ public class SearchdomainController : ControllerBase
{"settings", settings},
{"id", searchdomain_.id}
};
searchdomain_.helper.ExecuteSQLNonQuery("UPDATE searchdomain set name = @name, settings = @settings WHERE id = @id", parameters);
await searchdomain_.helper.ExecuteSQLNonQuery("UPDATE searchdomain set name = @name, settings = @settings WHERE id = @id", parameters);
}
return Ok(new SearchdomainUpdateResults(){Success = true});
}
@@ -230,8 +230,9 @@ public class SearchdomainController : ControllerBase
/// Update the settings of a searchdomain
/// </summary>
/// <param name="searchdomain">Name of the searchdomain</param>
/// <param name="request">Settings to apply to the searchdomain</param>
[HttpPut("Settings")]
public ActionResult<SearchdomainUpdateResults> UpdateSettings([Required]string searchdomain, [Required][FromBody] SearchdomainSettings request)
public async Task<ActionResult<SearchdomainUpdateResults>> UpdateSettings([Required]string searchdomain, [Required][FromBody] SearchdomainSettings request)
{
(Searchdomain? searchdomain_, int? httpStatusCode, string? message) = SearchdomainHelper.TryGetSearchdomain(_domainManager, searchdomain, _logger);
if (searchdomain_ is null || httpStatusCode is not null) return StatusCode(httpStatusCode ?? 500, new SearchdomainUpdateResults(){Success = false, Message = message});
@@ -240,7 +241,7 @@ public class SearchdomainController : ControllerBase
{"settings", JsonSerializer.Serialize(request)},
{"id", searchdomain_.id}
};
searchdomain_.helper.ExecuteSQLNonQuery("UPDATE searchdomain set settings = @settings WHERE id = @id", parameters);
await searchdomain_.helper.ExecuteSQLNonQuery("UPDATE searchdomain set settings = @settings WHERE id = @id", parameters);
searchdomain_.settings = request;
searchdomain_.queryCache.Capacity = request.QueryCacheSize;
return Ok(new SearchdomainUpdateResults(){Success = true});

View File

@@ -68,7 +68,7 @@ public class ServerController : ControllerBase
elementCount++;
embeddingsCount += entry.Keys.Count;
}
var sqlHelper = DatabaseHelper.GetSQLHelper(_options.Value);
var sqlHelper = _searchdomainManager.helper;
var databaseTotalSize = DatabaseHelper.GetTotalDatabaseSize(sqlHelper);
Task<long> entityCountTask = DatabaseHelper.CountEntities(sqlHelper);
long queryCacheUtilization = 0;

View File

@@ -12,7 +12,7 @@ public class DatabaseHealthCheck : IHealthCheck
_searchdomainManager = searchdomainManager;
_logger = logger;
}
public Task<HealthCheckResult> CheckHealthAsync(
public async Task<HealthCheckResult> CheckHealthAsync(
HealthCheckContext context, CancellationToken cancellationToken = default)
{
try
@@ -22,23 +22,23 @@ public class DatabaseHealthCheck : IHealthCheck
catch (Exception ex)
{
_logger.LogCritical("DatabaseHealthCheck - Exception occurred when retrieving and parsing database version: {ex}", ex.Message);
return Task.FromResult(
return await Task.FromResult(
HealthCheckResult.Unhealthy());
}
try
{
_searchdomainManager.helper.ExecuteSQLNonQuery("INSERT INTO settings (name, value) VALUES ('test', 'x');", []);
_searchdomainManager.helper.ExecuteSQLNonQuery("DELETE FROM settings WHERE name = 'test';", []);
await _searchdomainManager.helper.ExecuteSQLNonQuery("INSERT INTO settings (name, value) VALUES ('test', 'x');", []);
await _searchdomainManager.helper.ExecuteSQLNonQuery("DELETE FROM settings WHERE name = 'test';", []);
}
catch (Exception ex)
{
_logger.LogCritical("DatabaseHealthCheck - Exception occurred when executing INSERT/DELETE query: {ex}", ex.Message);
return Task.FromResult(
return await Task.FromResult(
HealthCheckResult.Unhealthy());
}
return Task.FromResult(
return await Task.FromResult(
HealthCheckResult.Healthy());
}
}

View File

@@ -23,11 +23,10 @@ public class Searchdomain
public ConcurrentDictionary<string, Entity> entityCache;
public ConcurrentBag<string> modelsInUse;
public EnumerableLruCache<string, Dictionary<string, float[]>> embeddingCache;
private readonly MySqlConnection connection;
public SQLHelper helper;
private readonly ILogger _logger;
public Searchdomain(string searchdomain, string connectionString, AIProvider aIProvider, EnumerableLruCache<string, Dictionary<string, float[]>> embeddingCache, ILogger logger, string provider = "sqlserver", bool runEmpty = false)
public Searchdomain(string searchdomain, string connectionString, SQLHelper sqlHelper, AIProvider aIProvider, EnumerableLruCache<string, Dictionary<string, float[]>> embeddingCache, ILogger logger, string provider = "sqlserver", bool runEmpty = false)
{
_connectionString = connectionString;
_provider = provider.ToLower();
@@ -36,9 +35,7 @@ public class Searchdomain
this.embeddingCache = embeddingCache;
this._logger = logger;
entityCache = [];
connection = new MySqlConnection(connectionString);
connection.Open();
helper = new SQLHelper(connection, connectionString);
helper = sqlHelper;
settings = GetSettings();
queryCache = new(settings.QueryCacheSize);
modelsInUse = []; // To make the compiler shut up - it is set in UpdateSearchDomain() don't worry // yeah, about that...

View File

@@ -58,7 +58,7 @@ public class SearchdomainManager : IDisposable
}
try
{
return SetSearchdomain(searchdomain, new Searchdomain(searchdomain, connectionString, aIProvider, embeddingCache, _logger));
return SetSearchdomain(searchdomain, new Searchdomain(searchdomain, connectionString, helper, aIProvider, embeddingCache, _logger));
}
catch (MySqlException)
{
@@ -101,7 +101,9 @@ public class SearchdomainManager : IDisposable
{ "name", searchdomain },
{ "settings", settings}
};
return await helper.ExecuteSQLCommandGetInsertedID("INSERT INTO searchdomain (name, settings) VALUES (@name, @settings)", parameters);
int id = await helper.ExecuteSQLCommandGetInsertedID("INSERT INTO searchdomain (name, settings) VALUES (@name, @settings)", parameters);
searchdomains.Add(searchdomain, new(searchdomain, connectionString, helper, aIProvider, embeddingCache, _logger));
return id;
}
public async Task<int> DeleteSearchdomain(string searchdomain)