Interfaccia di pubblicazione dei messaggi durante il differimento fino al commit della transazione

5

Supponiamo di avere la seguente interfaccia utilizzata per pubblicare messaggi su una coda di messaggi:

interface IMessageProducer
{
    void Publish<TMessage>(TMessage message);
}

Normalmente, un implementatore di questa interfaccia tenterà di pubblicare immediatamente un messaggio nella coda dei messaggi. Tuttavia, ho riscontrato che a volte ho bisogno che i messaggi vengano posticipati pubblicati fino a quando la transazione del database non è stata commessa (questo garantisce che i dati utilizzati nel gestore messaggi siano disponibili nel database).

È appropriato rendere esplicito questo comportamento allo sviluppatore? Ad esempio, estendendo l'interfaccia:

interface IMessageProducer
{
    void Publish<TMessage>(TMessage message);
    void DeferPublishUntilTransactionCommit<TMessage>(ITransaction transaction, TMessage message);
}

O creando un'interfaccia aggiuntiva che aggiunge questo comportamento (o anche un metodo di estensione all'interfaccia IMessageProducer ):

interface IDeferUntilTransactionCommitMessageProducer
{
    void DeferPublish<TMessage>(ITransaction transaction, TMessage message);
}

La mia ipotesi è errata? Questo è davvero un dettaglio di implementazione in cui non c'è motivo di esporlo allo sviluppatore? Ho trovato molto utile (aumentare la chiarezza) rendere l'interfaccia esplicita sull'intento in modo che lo sviluppatore comprenda perché è importante rimandare la pubblicazione fino a quando la transazione non è stata commessa. Altrimenti, se si tratta di una preoccupazione trasversale e di un dettaglio di implementazione, diventa un problema di configurazione che può avere un impatto significativo sull'applicazione in esecuzione. Ho visto altri software / librerie che fanno queste scelte (come usare il commit a due fasi) un dettaglio di implementazione dell'interfaccia piuttosto che esplicito.

    
posta TheCloudlessSky 17.11.2016 - 05:10
fonte

1 risposta

1

Suggerisco di incapsulare il comportamento di differimento in un decoratore :

public class TransactionDeferral : IMessageProducer
{
    public TransactionDeferral(IMessageProducer decoratedMessageProducer, ITransaction deferringTransaction)
    {
        _decoratedMessageProducer = decoratedMessageProducer;
        _deferringTransaction = deferringTransaction;
    }

    public void Publish<TMessage>(TMessage message)
    {
        if (_deferringTransaction.IsCommitted)
            _decoratedMessageProducer.Publish(message);
        else
            _deferredMessages.Add(message);
    }

    private void DeferringTransaction_Committed(obsect sender, TransactionCommitedEventArgs e)
    {
        foreach (var message in _deferredMessages)
        {
            _decoratedMessageProducer.Publish(message);
        }
    }
}

Il consumatore di questa interfaccia può quindi essere iniettato un IMessagePublisher che è in realtà un'istanza di TransactionDeferral che decora il vero editore di messaggi, diventando così completamente indipendente dalla transazione.

Se il consumatore deve essere a conoscenza del completamento delle singole operazioni di pubblicazione dei messaggi, probabilmente potresti modificare l'interfaccia originale per il suo metodo Publish per restituire un Task che può essere alla fine await ed:

public interface IMessageProducer
{
    Task Publish<TMessage>(TMessage message);
}
    
risposta data 17.11.2016 - 23:35
fonte

Leggi altre domande sui tag