web-dev-qa-db-fra.com

Synchronisation des transactions au printemps Kafka

Je souhaite synchroniser une transaction kafka avec une transaction de référentiel:

@Transactional
public void syncTransaction(){
  myRepository.save(someObject)
  kafkaTemplate.send(someEvent)
}

Depuis la fusion ( https://github.com/spring-projects/spring-kafka/issues/37 ) et selon le doc c'est possible. Néanmoins, j'ai des problèmes pour comprendre et implémenter cette fonctionnalité. En regardant l'exemple dans https://docs.spring.io/spring-kafka/reference/htmlsingle/#_transaction_synchronization Je dois créer un MessageListenerContainer pour écouter mes propres événements. Dois-je quand même envoyer mes événements en utilisant le KafkaTemplate? Le MessageListenerContainer interdit-il l'envoi au courtier?

Et si je comprends bien, le kafkaTemplate et le kafkaTransactionManager doivent utiliser le même producteurFactory dans lequel je dois activer Transaction en définissant un transactionIdPrefix. Et dans mon exemple, je dois définir le TransactionManager de messageListenerContainer sur DataSourceTransactionManager. Est-ce exact?

De mon point de vue, il semble étrange que j'envoie un événement via kafkaTemplate, que j'écoute mon propre événement et que je transmette l'événement à nouveau à l'aide de kafkaTemplate.

Je voudrais vraiment m'aider si je peux obtenir un exemple de synchronisation simple d'une transaction kafka avec une transaction de référentiel et une explication.

7
Eike Behrends

Si le conteneur d'écoute est provisionné avec un KafkaTransactionManager, le conteneur créera un producteur qui sera utilisé par n'importe quel modèle en aval kafka modèle et le conteneur enverra les décalages à la transaction pour tu.

Si le conteneur possède un autre gestionnaire de transactions, le conteneur ne peut pas envoyer les décalages car il n'a pas accès au producteur (ou au modèle).

Une autre solution consiste à annoter votre méthode avec @Transactional (avec la source de données TM) et configurez le conteneur avec une kafka TM.

De cette façon, votre DB tx sera validé juste avant que le thread ne revienne au conteneur qui enverra ensuite les décalages à la transaction kafka et la validera.

Voir les cas de test du framework pour des exemples.

8
Gary Russell

@Eike Behrends pour avoir une transaction db + kafka, vous pouvez utiliser ChainedTransactionManager et la définir de cette façon:

@Bean
public KafkaTransactionManager kafkaTransactionManager() {
    KafkaTransactionManager ktm = new KafkaTransactionManager(producerFactory());;
    ktm.setTransactionSynchronization(AbstractPlatformTransactionManager.SYNCHRONIZATION_ON_ACTUAL_TRANSACTION);
    return ktm;
}


@Bean
@Primary
public JpaTransactionManager transactionManager(EntityManagerFactory em) {
    return new JpaTransactionManager(em);
}

@Bean(name = "chainedTransactionManager")
public ChainedTransactionManager chainedTransactionManager(JpaTransactionManager jpaTransactionManager,
                                                           KafkaTransactionManager kafkaTransactionManager) {
    return new ChainedTransactionManager(kafkaTransactionManager, jpaTransactionManager);
}

Vous devez annoter vos méthodes transactionnelles db + kafka @Transactional("chainedTransactionManager")

(vous pouvez voir le problème sur le projet spring-kafka: https://github.com/spring-projects/spring-kafka/issues/4 )

Vous dites :

De mon point de vue, il semble étrange que j'envoie un événement via kafkaTemplate, que j'écoute mon propre événement et que je transmette l'événement à nouveau à l'aide de kafkaTemplate.

Avez-vous essayé cela? Si oui, pouvez-vous fournir un exemple, s'il vous plaît?

3
nader.h