Interface de publicação de mensagens ao adiar até que a transação seja confirmada

5

Suponha que eu tenha a seguinte interface usada para publicar mensagens em uma fila de mensagens:

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

Normalmente, um implementador dessa interface tentará publicar uma mensagem na fila de mensagens imediatamente. No entanto, descobri que às vezes preciso que as mensagens sejam adiadas sendo publicadas até que a transação do banco de dados seja confirmada (isso garante que os dados usados no manipulador de mensagens estejam disponíveis no banco de dados).

É apropriado tornar esse comportamento explícito para o desenvolvedor? Por exemplo, estendendo a interface:

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

Ou fazendo uma interface adicional que adicione esse comportamento (ou até mesmo um método de extensão na interface IMessageProducer ):

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

Minha suposição está errada? Esse é realmente um detalhe de implementação em que não há motivo para expô-lo ao desenvolvedor? Eu achei muito útil (aumentar a clareza) para tornar a interface explícita sobre a intenção para que o desenvolvedor entenda por que é importante adiar a publicação até que a transação seja confirmada. Caso contrário, se for uma preocupação transversal e um detalhe de implementação, isso se torna um problema de configuração que pode afetar significativamente o aplicativo em execução. Eu vi outros softwares / bibliotecas que fazem essas escolhas (como usar two phase commit) um detalhe de implementação da interface, em vez de explícito.

    
por TheCloudlessSky 17.11.2016 / 05:10
fonte

1 resposta

1

Eu sugeriria encapsular o comportamento de adiamento em um decorador :

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);
        }
    }
}

O consumidor dessa interface pode ser então injetado um IMessagePublisher que é na realidade uma instância de TransactionDeferral decorando o verdadeiro publicador de mensagens, tornando-se assim completamente agnóstico da transação.

Se o consumidor tiver que estar ciente da conclusão das operações de publicação de mensagens individuais, provavelmente você poderá modificar sua interface original para o método Publish para retornar um Task que pode ser eventualmente await ed:

public interface IMessageProducer
{
    Task Publish<TMessage>(TMessage message);
}
    
por 17.11.2016 / 23:35
fonte