J'écris une application de base pour tester la fonctionnalité de requêtes interactives de Kafka Streams. Voici le code:
public static void main (String [] args) {
StreamsBuilder builder = new StreamsBuilder();
KeyValueBytesStoreSupplier waypointsStoreSupplier = Stores.persistentKeyValueStore("test-store");
StoreBuilder waypointsStoreBuilder = Stores.keyValueStoreBuilder(waypointsStoreSupplier, Serdes.ByteArray(), Serdes.Integer());
final KStream<byte[], byte[]> waypointsStream = builder.stream("sample1");
final KStream<byte[], TruckDriverWaypoint> waypointsDeserialized = waypointsStream
.mapValues(CustomSerdes::deserializeTruckDriverWaypoint)
.filter((k,v) -> v.isPresent())
.mapValues(Optional::get);
waypointsDeserialized.groupByKey().aggregate(
() -> 1,
(aggKey, newWaypoint, aggValue) -> {
aggValue = aggValue + 1;
return aggValue;
}, Materialized.<byte[], Integer, KeyValueStore<Bytes, byte[]>>as("test-store").withKeySerde(Serdes.ByteArray()).withValueSerde(Serdes.Integer())
);
final KafkaStreams streams = new KafkaStreams(builder.build(), new StreamsConfig(createStreamsProperties()));
streams.cleanUp();
streams.start();
ReadOnlyKeyValueStore<byte[], Integer> keyValueStore = streams.store("test-store", QueryableStoreTypes.keyValueStore());
KeyValueIterator<byte[], Integer> range = keyValueStore.all();
while (range.hasNext()) {
KeyValue<byte[], Integer> next = range.next();
System.out.println(next.value);
}
Runtime.getRuntime().addShutdownHook(new Thread(streams::close));
}
protected static Properties createStreamsProperties() {
final Properties streamsConfiguration = new Properties();
streamsConfiguration.put(StreamsConfig.APPLICATION_ID_CONFIG, "random167");
streamsConfiguration.put(StreamsConfig.CLIENT_ID_CONFIG, "client-id");
streamsConfiguration.put(StreamsConfig.BOOTSTRAP_SERVERS_CONFIG, "localhost:9092");
streamsConfiguration.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
streamsConfiguration.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, Serdes.String().getClass().getName());
streamsConfiguration.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, Serdes.Integer().getClass().getName());
//streamsConfiguration.put(StreamsConfig.COMMIT_INTERVAL_MS_CONFIG, 10000);
return streamsConfiguration;
}
Donc, mon problème est que chaque fois que je lance ceci, je reçois la même erreur:
Exception in thread "main" org.Apache.kafka.streams.errors.InvalidStateStoreException: the state store, test-store, may have migrated to another instance.
J'exécute une seule instance de l'application et le sujet que je consomme n'a qu'une seule partition.
Une idée de ce que je fais mal?
On dirait que vous avez une condition de course. Dans le flux javadoc javadoc pour KafkaStreams::start()
, il est indiqué:
Démarrez l'instance KafkaStreams en lançant tous ses threads. Cette fonction ne devrait être appelée qu'une fois au cours du cycle de vie du client. Les threads étant démarrés en arrière-plan, cette méthode ne bloque pas.
https://kafka.Apache.org/10/javadoc/index.html?org/Apache/kafka/streams/KafkaStreams.html
Vous appelez streams.store()
immédiatement après streams.start()
, mais je parierais que vous êtes dans un état où il n'a pas encore été initialisé complètement.
Puisque ce code semble être juste pour le test, ajoutez une Thread.sleep(5000)
ou quelque chose dedans et essayez-le. (Ce n'est pas une solution pour la production) En fonction de votre débit d'entrée dans le sujet, cela laissera probablement un peu de temps au magasin pour commencer à se remplir d'événements, de sorte que votre KeyValueIterator
ait réellement quelque chose à traiter/imprimer.
Probablement pas applicable à OP mais pourrait aider les autres:
En essayant de récupérer un magasin KTable, assurez-vous que le sujet de KTable existe en premier ou vous obtiendrez cette exception.
J'ai échoué à appeler Storebuilder
avant de consommer le magasin.