У меня есть группа «рабочих», которым в какой-то момент нужен уникальный ключ от моего HTTP-сервера для продолжения выполнения. Эти ключи иногда могут поступать до того, как они понадобятся рабочим, и в этом случае я просто хочу предоставить работнику ключ, чтобы он мог продолжить выполнение. Однако если ключей не осталось, я хочу, чтобы выполнение кода в задаче было остановлено до тех пор, пока не будет предоставлен ключ. Я также хочу, чтобы ключи, которые были предоставлены первыми, использовались первыми.
Я пытался внедрить Singleton, где ключи могут быть переданы с HTTP-сервера и извлечены рабочими, но выполнение кажется заблокированным прямо сейчас.
Мой код:
Keyhandler.cs
public sealed class KeyHandler
{
private static readonly KeyHandler instance = new KeyHandler();
private static Dictionary<Website, Queue<string>> retrievedKeys = new Dictionary<Website, Queue<string>>();
private static Dictionary<Website, Queue<TaskCompletionSource<string>>> waitingWorkers = new Dictionary<Website, Queue<TaskCompletionSource<string>>>();
// Explicit static constructor to tell C# compiler
// not to mark type as beforefieldinit
static KeyHandler()
{
}
private KeyHandler()
{
foreach (Website website in Enum.GetValues(typeof(Website)))
{
retrievedKeys.Add(website, new Queue<string>());
waitingWorkers.Add(website, new Queue<TaskCompletionSource<string>>());
}
}
public static KeyHandler Instance
{
get
{
return instance;
}
}
public static void AddKey(Website website, string response)
{
if (waitingWorkers[website].Count > 0)
{
waitingWorkers[website].Dequeue().SetResult(response);
}
else
{
retrievedKeys[website].Enqueue(response);
}
}
public static string RetrieveKey(Website website)
{
if (retrievedKeys[website].Count > 0)
{
return retrievedKeys[website].Dequeue();
}
else
{
TaskCompletionSource<string> tcs = new TaskCompletionSource<string>();
Task<string> t = tcs.Task;
waitingWorkers[website].Enqueue(tcs);
return t.Result;
}
}
}
Worker.cs
public async Task Run()
{
...
string key = KeyHandler.RetrieveKey(Website.MyWebsite);
// do something with key here
...
}
HTTPServer.cs
private void Process(HttpListenerContext context)
{
...
KeyHandler.AddKey(Website.MyWebsite, key);
...
}