Siamo nuovi in c # e stiamo ancora cercando di ingannare gli idiomi asincroni.
Abbiamo un servizio Windows che ci richiede di iterare un elenco di risultati interrogati da un database PC per alimentare il server cloud parse (che supporta solo letture e scritture asincrone). I risultati devono essere sovrascritti con nuovi risultati.
In un sdk java legacy, abbiamo semplicemente fatto:
For each result:
do synchronous find
if not found
create a new object/document
else
Update the existing object/document
Save synchronously
e non ha avuto problemi.
BTW - il nostro server ha bisogno di alimentare Parse in pochi secondi, non in microsecondi, anche se le prestazioni al secondo posto non farebbero male!
Il nostro attuale sistema di produzione utilizzava lock () per garantire che la lettura / scrittura rimanesse sincronizzata, tuttavia sospettiamo che si verifichino deadlock . Un dato di fatto è che riavviare il servizio elabora la coda dei comandi bene !!
La nostra soluzione proposta è simile a questa:
private readonly SemaphoreSlim _mutex = new SemaphoreSlim(1);
public async Task ProcessPostedCommandsAsync()
{
using (var showContext = new ShowContext())
{
var retryCnt = 0;
var maxRetries = 8;
var commands = FindCommands(showContext);
foreach (var command in commands)
{
await _mutex.WaitAsync();
try
{
// read data from the cloud,
// based on data from the cloud, write back to the cloud
// mark the command as processed in the database
await ProcessCommandAsync(showContext, command);
}
catch (Exception e)
{
GlobalLogger.Logger.Error(e,
$"assinging executing task, Exception in Process Commands pkid = {command.Pkid} ");
GlobalLogger.Logger.Error($"Retry count = {retryCnt}");
retryCnt++;
await Task.Delay(2000);
if (retryCnt == maxRetries)
{
break; // from for
}
}
finally
{
_mutex.Release();
}
}
}
}
Da allora abbiamo modificato il nostro codice per risolvere il problema del deadlock utilizzando il SemaphoreSlim.
Con un solo comando nel database, chiamiamolo Command-A, sembra che la duplicazione si verifichi quando il ciclo di lettura dei comandi rilegge Command-A anche se Command-A ha già dato il via al suo read / write cloud.
Ovunque guardiamo dice: "NON BLOCCA o si bloccheranno" e dice "async" / attendi fino in fondo. Ma se non blocchiamo in qualche modo otterremo condizioni di gara e duplicati.
Quindi abbiamo aggiunto i blocchi e otteniamo ciò che sembra un deadlock dopo ore di elaborazione dei comandi.
Questo sembra un caso d'uso piuttosto comune.
1) Esiste un idioma c # che manca qui che scorre in un elenco di comandi per scrivere in modo asincrono nel cloud ma in ordine sequenziale senza inviare duplicati e non creare deadlock? Vogliamo solo un modo per attendere che ogni comando sincronizzato finisca.
2) Come possiamo testarlo in modo tale da dimostrare che funziona in ambienti diversi.
Ci sentiamo veramente in una situazione Catch 22 . Dobbiamo bloccare per attendere che il comando venga elaborato completamente mentre ancora non dovremmo bloccare il codice asincrono.
Nota: abbiamo esaminato le seguenti risorse e stiamo cercando la direzione fino ad ora.