Scenario
Il mio progetto ha la necessità di analizzare periodicamente il database e notificare agli amministratori problemi particolari. Ad esempio:
- Qualche errore nei log dall'ultimo aggiornamento?
- I valori corrispondono al valore atteso dalla fonte esterna?
- Nuovi clienti?
I miei nodi (normali vecchi servizi Windows) stanno attualmente utilizzando il bus di servizio di Azure QueueClient per altre attività distribuite, quindi il mio pensiero iniziale era di fare qualcosa con questo stesso componente. Tuttavia, questo si è rivelato piuttosto impegnativo (vedi sotto).
Dal brainstorming ho trovato le seguenti opzioni possibili:
Azure ServiceBus QueueClient
Descrizione: dopo aver ricevuto un'attività, il gestore messaggi accoderà un nuovo set di messaggi per X in futuro.
Ad esempio:
var client = QueueClient.Create("DetectErrors");
var options = /* ... */
client.OnMessage((message) => {
client.Send(new BrokeredMessage() {
ScheduledEnqueueTimeUtc = DateTime.Today.AddDays(1)
});
if (DetectStuffInDb())
{
SendEmail();
}
}, options)
Problema: Come sparare quel primo messaggio? Questo deve essere attivato quando non ci sono messaggi in sospeso e si attiva solo un singolo messaggio (non uno per nodo come potrebbe essere il caso se tutti i nodi iniziano contemporaneamente)
Azure QueueClient + WebJob
Descrizione: Usa un Webjob di Azure per colpire un endpoint sul mio WebApi, che accoderà un nuovo messaggio. (una leggera derivazione di ciò sarebbe l'utilizzo di Azure Automation + Runbook per accodare un messaggio)
Problema: Sembra strano fare così tanti "salti" per gestire ogni attività. %codice%. Inoltre, ciò renderebbe difficile lo sviluppo \ testing poiché il WebJob potrebbe non avere accesso a un WebApi localhost.
Task.Delay + DB
Descrizione: utilizza Task.Delay per distribuire attività ricorrenti su ciascun nodo distribuito & verificare con il DB se un altro nodo sta attualmente gestendo l'attività. Qualcosa come
var id = Cmd("SELECT [Id] FROM [T]");
while (true)
{
var newId = Guid.NewGuid();
Cmd("UPDATE [T] SET [Id] = '<newId>' WHERE [Id] = '<id>'");
id = Cmd("SELECT [Id] FROM [T]");
if (newId == id)
{
if (DetectStuffInDb())
{
SendEmail();
}
}
await Task.Delay(x);
}
Problemi: richiede molte query sul database da parte di tutti i nodi.
Domanda
- Qualche suggerimento su come gestire al meglio questo scenario?
- Esiste un modo migliore per gestire questo scenario che non richiede attività a tempo / ricorrenti?