-
Notifications
You must be signed in to change notification settings - Fork 54
Якшибаев Данил, ДЗ №2 #70
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
base: master
Are you sure you want to change the base?
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,23 +1,86 @@ | ||
| using System; | ||
| using System.Collections.Concurrent; | ||
| using System.Collections.Generic; | ||
| using System.Diagnostics; | ||
| using System.Linq; | ||
| using System.Text; | ||
| using System.Threading.Tasks; | ||
| using log4net; | ||
|
|
||
| namespace ClusterClient.Clients | ||
| { | ||
| public class SmartClusterClient : ClusterClientBase | ||
| { | ||
| private readonly ConcurrentDictionary<string, long> _replicaTimings = new(); | ||
|
|
||
| public SmartClusterClient(string[] replicaAddresses) : base(replicaAddresses) | ||
| { | ||
| foreach (var replicaAddress in replicaAddresses) | ||
| { | ||
| _replicaTimings.TryAdd(replicaAddress, 0); | ||
| } | ||
| } | ||
|
|
||
| public override Task<string> ProcessRequestAsync(string query, TimeSpan timeout) | ||
| public override async Task<string> ProcessRequestAsync(string query, TimeSpan timeout) | ||
| { | ||
| throw new NotImplementedException(); | ||
| var stopwatch = Stopwatch.StartNew(); | ||
| var replicasLeft = ReplicaAddresses.Length; | ||
|
|
||
| var sortedReplicas = ReplicaAddresses | ||
| .OrderBy(a => _replicaTimings.GetValueOrDefault(a, long.MaxValue)) | ||
| .ToList(); | ||
|
|
||
| Log.Debug($"Replica order: {string.Join(", ", sortedReplicas)}"); | ||
|
|
||
| var pendingRequests = new List<Task<string>>(); | ||
|
|
||
| foreach (var replicaAddress in sortedReplicas) | ||
| { | ||
| var timeoutPerReplica = (timeout - stopwatch.Elapsed) / replicasLeft--; | ||
|
|
||
| Log.Debug($"Starting request to {replicaAddress}. Timeout per replica: " + | ||
| $"{timeoutPerReplica.TotalMilliseconds} ms"); | ||
|
|
||
| pendingRequests.Add(ProcessReplicaAsync(replicaAddress, query)); | ||
| var completedTask = await WaitForReplicaAndLogAsync(pendingRequests, timeoutPerReplica); | ||
| _replicaTimings[replicaAddress] = stopwatch.ElapsedMilliseconds; | ||
|
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. А здесь уже количество ошибок выросло до трех:
|
||
|
|
||
| if (completedTask is not { IsCompletedSuccessfully: true }) | ||
| { | ||
| continue; | ||
| } | ||
|
|
||
| Log.Info($"Replica responded successfully in {stopwatch.ElapsedMilliseconds} ms"); | ||
| return await completedTask; | ||
| } | ||
|
|
||
| Log.Debug("Initial replica attempts finished. Waiting for remaining pending requests"); | ||
|
|
||
| while (pendingRequests.Count > 0) | ||
|
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. А в цикле ожидания завершения задач мы в принципе не запишем никакую статистику. В итоге статистика у нас не имеет ничего общего с реальностью |
||
| { | ||
| var remainingTime = timeout - stopwatch.Elapsed; | ||
|
|
||
| if (remainingTime <= TimeSpan.Zero) | ||
| { | ||
| Log.Debug("Global timeout reached while waiting for pending replicas"); | ||
| break; | ||
| } | ||
|
|
||
| Log.Debug($"Waiting for pending replicas. Remaining: {pendingRequests.Count}"); | ||
| var completedTask = await WaitForReplicaAndLogAsync(pendingRequests, remainingTime); | ||
|
|
||
| if (completedTask is not { IsCompletedSuccessfully: true }) | ||
| { | ||
| continue; | ||
| } | ||
|
|
||
| Log.Info($"Pending replica responded successfully in {stopwatch.ElapsedMilliseconds} ms"); | ||
| return await completedTask; | ||
| } | ||
|
|
||
| Log.Error("All replicas failed or timed out"); | ||
| throw new TimeoutException(); | ||
| } | ||
|
|
||
| protected override ILog Log => LogManager.GetLogger(typeof(SmartClusterClient)); | ||
| } | ||
| } | ||
| } | ||
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.
Тут сразу два типа ошибки:
Поэтому третья реплика будь она самой быстрой
"на диком западе"не окажется первой в списке при повторной отправке запрос через этот клиент