-
-
Notifications
You must be signed in to change notification settings - Fork 622
BuildRetryPolicy for reliable membase #1315
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,12 +1,6 @@ | ||
| using BotSharp.Abstraction.Graph; | ||
| using BotSharp.Abstraction.Graph.Models; | ||
| using BotSharp.Abstraction.Graph.Options; | ||
| using BotSharp.Abstraction.Models; | ||
| using BotSharp.Abstraction.Options; | ||
| using BotSharp.Abstraction.Utilities; | ||
| using BotSharp.Plugin.Membase.Interfaces; | ||
| using Microsoft.Extensions.Logging; | ||
| using System.Text.Json; | ||
| using Polly; | ||
| using Polly.Timeout; | ||
| using Refit; | ||
|
|
||
| namespace BotSharp.Plugin.Membase.GraphDb; | ||
|
|
||
|
|
@@ -28,6 +22,33 @@ public MembaseGraphDb( | |
|
|
||
| public string Provider => "membase"; | ||
|
|
||
| private const int RetryCount = 3; | ||
|
|
||
| private AsyncPolicy BuildRetryPolicy() | ||
| { | ||
| var settings = _services.GetRequiredService<MembaseSettings>(); | ||
| var timeoutSeconds = (double)settings.TimeoutSecond / RetryCount; | ||
|
|
||
| var timeoutPolicy = Policy.TimeoutAsync(TimeSpan.FromSeconds(timeoutSeconds)); | ||
|
|
||
| var retryPolicy = Policy | ||
| .Handle<HttpRequestException>() | ||
| .Or<TaskCanceledException>() | ||
| .Or<TimeoutRejectedException>() | ||
| .Or<ApiException>(ex => ex.StatusCode == HttpStatusCode.ServiceUnavailable) | ||
| .WaitAndRetryAsync( | ||
| retryCount: RetryCount, | ||
| sleepDurationProvider: retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), | ||
| onRetry: (ex, timespan, retryAttempt, _) => | ||
| { | ||
| _logger.LogWarning(ex, | ||
| "CypherQueryAsync retry {RetryAttempt}/{MaxRetries} after {Delay}s. Exception: {Message}", | ||
| retryAttempt, RetryCount, timespan.TotalSeconds, ex.Message); | ||
| }); | ||
|
|
||
| return Policy.WrapAsync(retryPolicy, timeoutPolicy); | ||
| } | ||
|
|
||
| public async Task<GraphQueryResult> ExecuteQueryAsync(string query, GraphQueryExecuteOptions? options = null) | ||
| { | ||
| if (string.IsNullOrEmpty(options?.GraphId)) | ||
|
|
@@ -36,14 +57,17 @@ public async Task<GraphQueryResult> ExecuteQueryAsync(string query, GraphQueryEx | |
| } | ||
|
|
||
| var args = options?.Arguments ?? new(); | ||
| var argLogs = JsonSerializer.Serialize(args, BotSharpOptions.defaultJsonOptions); | ||
|
|
||
| try | ||
| { | ||
| var response = await _membaseApi.CypherQueryAsync(options!.GraphId, new CypherQueryRequest | ||
| { | ||
| Query = query, | ||
| Parameters = args | ||
| }); | ||
| var retryPolicy = BuildRetryPolicy(); | ||
| var response = await retryPolicy.ExecuteAsync(() => | ||
| _membaseApi.CypherQueryAsync(options!.GraphId, new CypherQueryRequest | ||
|
Comment on lines
59
to
+66
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 3. Args serialization can break queries ExecuteQueryAsync serializes options.Arguments before entering the try/catch, so a serialization failure will throw and prevent the Membase query from running. Since Arguments is Dictionary<string, object>, callers can provide values that are not JSON-serializable. Agent Prompt
|
||
| { | ||
| Query = query, | ||
| Parameters = args | ||
| })); | ||
|
|
||
| return new GraphQueryResult | ||
| { | ||
|
|
@@ -52,10 +76,14 @@ public async Task<GraphQueryResult> ExecuteQueryAsync(string query, GraphQueryEx | |
| Result = JsonSerializer.Serialize(response.Data) | ||
| }; | ||
| } | ||
| catch (ApiException ex) | ||
| { | ||
| _logger.LogError($"Error when executing query in {Provider} graph db:\r\n{ex.Content}\r\n{query}\r\n{argLogs}"); | ||
| throw; | ||
|
Comment on lines
+79
to
+82
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 1. Logs ex.content and query New error logging writes raw ex.Content, query, and serialized args (argLogs), which can include sensitive user/model content and internal details. This increases risk of sensitive data exposure through logs. Agent Prompt
|
||
| } | ||
| catch (Exception ex) | ||
| { | ||
| var argLogs = args.Select(x => (new KeyValue(x.Key, x.Value.ConvertToString(BotSharpOptions.defaultJsonOptions))).ToString()); | ||
| _logger.LogError(ex, $"Error when executing query in {Provider} graph db. (Query: {query}), (Argments: \r\n{string.Join("\r\n", argLogs)})"); | ||
| _logger.LogError(ex, $"Error when executing query in {Provider} graph db. (Query: {query}), (Argments: \r\n{argLogs})"); | ||
| throw; | ||
| } | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
2. Configured timeout not honored
🐞 Bug⛯ ReliabilityAgent Prompt
ⓘ Copy this prompt and use it to remediate the issue with your preferred AI generation tools