Search in sources :

Example 1 with InvalidOffsetException

use of org.apache.kafka.clients.consumer.InvalidOffsetException in project apache-kafka-on-k8s by banzaicloud.

the class StoreChangelogReaderTest method shouldRecoverFromInvalidOffsetExceptionAndFinishRestore.

@Test
public void shouldRecoverFromInvalidOffsetExceptionAndFinishRestore() {
    final int messages = 10;
    setupConsumer(messages, topicPartition);
    consumer.setException(new InvalidOffsetException("Try Again!") {

        @Override
        public Set<TopicPartition> partitions() {
            return Collections.singleton(topicPartition);
        }
    });
    changelogReader.register(new StateRestorer(topicPartition, restoreListener, null, Long.MAX_VALUE, true, "storeName"));
    EasyMock.expect(active.restoringTaskFor(topicPartition)).andReturn(task);
    EasyMock.replay(active);
    // first restore call "fails" but we should not die with an exception
    assertEquals(0, changelogReader.restore(active).size());
    // retry restore should succeed
    assertEquals(1, changelogReader.restore(active).size());
    assertThat(callback.restored.size(), equalTo(messages));
}
Also used : Set(java.util.Set) InvalidOffsetException(org.apache.kafka.clients.consumer.InvalidOffsetException) Test(org.junit.Test)

Example 2 with InvalidOffsetException

use of org.apache.kafka.clients.consumer.InvalidOffsetException in project apache-kafka-on-k8s by banzaicloud.

the class GlobalStreamThreadTest method shouldDieOnInvalidOffsetException.

@Test
public void shouldDieOnInvalidOffsetException() throws Exception {
    initializeConsumer();
    globalStreamThread.start();
    TestUtils.waitForCondition(new TestCondition() {

        @Override
        public boolean conditionMet() {
            return globalStreamThread.state() == RUNNING;
        }
    }, 10 * 1000, "Thread never started.");
    mockConsumer.updateEndOffsets(Collections.singletonMap(topicPartition, 1L));
    mockConsumer.addRecord(new ConsumerRecord<>(GLOBAL_STORE_TOPIC_NAME, 0, 0L, "K1".getBytes(), "V1".getBytes()));
    TestUtils.waitForCondition(new TestCondition() {

        @Override
        public boolean conditionMet() {
            return mockConsumer.position(topicPartition) == 1L;
        }
    }, 10 * 1000, "Input record never consumed");
    mockConsumer.setException(new InvalidOffsetException("Try Again!") {

        @Override
        public Set<TopicPartition> partitions() {
            return Collections.singleton(topicPartition);
        }
    });
    // feed first record for recovery
    mockConsumer.addRecord(new ConsumerRecord<>(GLOBAL_STORE_TOPIC_NAME, 0, 0L, "K1".getBytes(), "V1".getBytes()));
    TestUtils.waitForCondition(new TestCondition() {

        @Override
        public boolean conditionMet() {
            return globalStreamThread.state() == DEAD;
        }
    }, 10 * 1000, "GlobalStreamThread should have died.");
}
Also used : Set(java.util.Set) TestCondition(org.apache.kafka.test.TestCondition) InvalidOffsetException(org.apache.kafka.clients.consumer.InvalidOffsetException) Test(org.junit.Test)

Example 3 with InvalidOffsetException

use of org.apache.kafka.clients.consumer.InvalidOffsetException in project apache-kafka-on-k8s by banzaicloud.

the class StreamThread method maybeUpdateStandbyTasks.

private void maybeUpdateStandbyTasks(final long now) {
    if (state == State.RUNNING && taskManager.hasStandbyRunningTasks()) {
        if (processStandbyRecords) {
            if (!standbyRecords.isEmpty()) {
                final Map<TopicPartition, List<ConsumerRecord<byte[], byte[]>>> remainingStandbyRecords = new HashMap<>();
                for (final Map.Entry<TopicPartition, List<ConsumerRecord<byte[], byte[]>>> entry : standbyRecords.entrySet()) {
                    final TopicPartition partition = entry.getKey();
                    List<ConsumerRecord<byte[], byte[]>> remaining = entry.getValue();
                    if (remaining != null) {
                        final StandbyTask task = taskManager.standbyTask(partition);
                        if (task.isClosed()) {
                            log.warn("Standby task {} is already closed, probably because it got unexpectly migrated to another thread already. " + "Notifying the thread to trigger a new rebalance immediately.", task.id());
                            throw new TaskMigratedException(task);
                        }
                        remaining = task.update(partition, remaining);
                        if (remaining != null) {
                            remainingStandbyRecords.put(partition, remaining);
                        } else {
                            restoreConsumer.resume(singleton(partition));
                        }
                    }
                }
                standbyRecords = remainingStandbyRecords;
                log.debug("Updated standby tasks {} in {}ms", taskManager.standbyTaskIds(), time.milliseconds() - now);
            }
            processStandbyRecords = false;
        }
        try {
            final ConsumerRecords<byte[], byte[]> records = restoreConsumer.poll(0);
            if (!records.isEmpty()) {
                for (final TopicPartition partition : records.partitions()) {
                    final StandbyTask task = taskManager.standbyTask(partition);
                    if (task == null) {
                        throw new StreamsException(logPrefix + "Missing standby task for partition " + partition);
                    }
                    if (task.isClosed()) {
                        log.warn("Standby task {} is already closed, probably because it got unexpectedly migrated to another thread already. " + "Notifying the thread to trigger a new rebalance immediately.", task.id());
                        throw new TaskMigratedException(task);
                    }
                    final List<ConsumerRecord<byte[], byte[]>> remaining = task.update(partition, records.records(partition));
                    if (remaining != null) {
                        restoreConsumer.pause(singleton(partition));
                        standbyRecords.put(partition, remaining);
                    }
                }
            }
        } catch (final InvalidOffsetException recoverableException) {
            log.warn("Updating StandbyTasks failed. Deleting StandbyTasks stores to recreate from scratch.", recoverableException);
            final Set<TopicPartition> partitions = recoverableException.partitions();
            for (final TopicPartition partition : partitions) {
                final StandbyTask task = taskManager.standbyTask(partition);
                if (task.isClosed()) {
                    log.warn("Standby task {} is already closed, probably because it got unexpectly migrated to another thread already. " + "Notifying the thread to trigger a new rebalance immediately.", task.id());
                    throw new TaskMigratedException(task);
                }
                log.info("Reinitializing StandbyTask {}", task);
                task.reinitializeStateStoresForPartitions(recoverableException.partitions());
            }
            restoreConsumer.seekToBeginning(partitions);
        }
    }
}
Also used : HashSet(java.util.HashSet) Set(java.util.Set) HashMap(java.util.HashMap) StreamsException(org.apache.kafka.streams.errors.StreamsException) InvalidOffsetException(org.apache.kafka.clients.consumer.InvalidOffsetException) ConsumerRecord(org.apache.kafka.clients.consumer.ConsumerRecord) TopicPartition(org.apache.kafka.common.TopicPartition) ArrayList(java.util.ArrayList) List(java.util.List) HashMap(java.util.HashMap) Map(java.util.Map) TaskMigratedException(org.apache.kafka.streams.errors.TaskMigratedException)

Example 4 with InvalidOffsetException

use of org.apache.kafka.clients.consumer.InvalidOffsetException in project apache-kafka-on-k8s by banzaicloud.

the class GlobalStateManagerImpl method restoreState.

private void restoreState(final StateRestoreCallback stateRestoreCallback, final List<TopicPartition> topicPartitions, final Map<TopicPartition, Long> highWatermarks, final String storeName) {
    for (final TopicPartition topicPartition : topicPartitions) {
        globalConsumer.assign(Collections.singletonList(topicPartition));
        final Long checkpoint = checkpointableOffsets.get(topicPartition);
        if (checkpoint != null) {
            globalConsumer.seek(topicPartition, checkpoint);
        } else {
            globalConsumer.seekToBeginning(Collections.singletonList(topicPartition));
        }
        long offset = globalConsumer.position(topicPartition);
        final Long highWatermark = highWatermarks.get(topicPartition);
        BatchingStateRestoreCallback stateRestoreAdapter = (BatchingStateRestoreCallback) ((stateRestoreCallback instanceof BatchingStateRestoreCallback) ? stateRestoreCallback : new WrappedBatchingStateRestoreCallback(stateRestoreCallback));
        stateRestoreListener.onRestoreStart(topicPartition, storeName, offset, highWatermark);
        long restoreCount = 0L;
        while (offset < highWatermark) {
            try {
                final ConsumerRecords<byte[], byte[]> records = globalConsumer.poll(100);
                final List<KeyValue<byte[], byte[]>> restoreRecords = new ArrayList<>();
                for (ConsumerRecord<byte[], byte[]> record : records) {
                    if (record.key() != null) {
                        restoreRecords.add(KeyValue.pair(record.key(), record.value()));
                    }
                    offset = globalConsumer.position(topicPartition);
                }
                stateRestoreAdapter.restoreAll(restoreRecords);
                stateRestoreListener.onBatchRestored(topicPartition, storeName, offset, restoreRecords.size());
                restoreCount += restoreRecords.size();
            } catch (final InvalidOffsetException recoverableException) {
                log.warn("Restoring GlobalStore {} failed due to: {}. Deleting global store to recreate from scratch.", storeName, recoverableException.getMessage());
                reinitializeStateStoresForPartitions(recoverableException.partitions(), processorContext);
                stateRestoreListener.onRestoreStart(topicPartition, storeName, offset, highWatermark);
                restoreCount = 0L;
            }
        }
        stateRestoreListener.onRestoreEnd(topicPartition, storeName, restoreCount);
        checkpointableOffsets.put(topicPartition, offset);
    }
}
Also used : KeyValue(org.apache.kafka.streams.KeyValue) TopicPartition(org.apache.kafka.common.TopicPartition) BatchingStateRestoreCallback(org.apache.kafka.streams.processor.BatchingStateRestoreCallback) ArrayList(java.util.ArrayList) InvalidOffsetException(org.apache.kafka.clients.consumer.InvalidOffsetException)

Example 5 with InvalidOffsetException

use of org.apache.kafka.clients.consumer.InvalidOffsetException in project apache-kafka-on-k8s by banzaicloud.

the class StreamThreadTest method shouldRecoverFromInvalidOffsetExceptionOnRestoreAndFinishRestore.

@Test
public void shouldRecoverFromInvalidOffsetExceptionOnRestoreAndFinishRestore() throws Exception {
    internalStreamsBuilder.stream(Collections.singleton("topic"), consumed).groupByKey().count(Materialized.<Object, Long, KeyValueStore<Bytes, byte[]>>as("count"));
    final StreamThread thread = createStreamThread("cliendId", config, false);
    final MockConsumer<byte[], byte[]> mockConsumer = (MockConsumer<byte[], byte[]>) thread.consumer;
    final MockConsumer<byte[], byte[]> mockRestoreConsumer = (MockConsumer<byte[], byte[]>) thread.restoreConsumer;
    final TopicPartition topicPartition = new TopicPartition("topic", 0);
    final Set<TopicPartition> topicPartitionSet = Collections.singleton(topicPartition);
    final Map<TaskId, Set<TopicPartition>> activeTasks = new HashMap<>();
    activeTasks.put(new TaskId(0, 0), topicPartitionSet);
    thread.taskManager().setAssignmentMetadata(activeTasks, Collections.<TaskId, Set<TopicPartition>>emptyMap());
    mockConsumer.updatePartitions("topic", new ArrayList<PartitionInfo>() {

        {
            add(new PartitionInfo("topic", 0, null, new Node[0], new Node[0]));
        }
    });
    mockConsumer.updateBeginningOffsets(Collections.singletonMap(topicPartition, 0L));
    mockRestoreConsumer.updatePartitions("stream-thread-test-count-changelog", new ArrayList<PartitionInfo>() {

        {
            add(new PartitionInfo("stream-thread-test-count-changelog", 0, null, new Node[0], new Node[0]));
        }
    });
    final TopicPartition changelogPartition = new TopicPartition("stream-thread-test-count-changelog", 0);
    final Set<TopicPartition> changelogPartitionSet = Collections.singleton(changelogPartition);
    mockRestoreConsumer.updateBeginningOffsets(Collections.singletonMap(changelogPartition, 0L));
    mockRestoreConsumer.updateEndOffsets(Collections.singletonMap(changelogPartition, 2L));
    mockConsumer.schedulePollTask(new Runnable() {

        @Override
        public void run() {
            thread.setState(StreamThread.State.PARTITIONS_REVOKED);
            thread.rebalanceListener.onPartitionsAssigned(topicPartitionSet);
        }
    });
    try {
        thread.start();
        TestUtils.waitForCondition(new TestCondition() {

            @Override
            public boolean conditionMet() {
                return mockRestoreConsumer.assignment().size() == 1;
            }
        }, "Never restore first record");
        mockRestoreConsumer.addRecord(new ConsumerRecord<>("stream-thread-test-count-changelog", 0, 0L, "K1".getBytes(), "V1".getBytes()));
        TestUtils.waitForCondition(new TestCondition() {

            @Override
            public boolean conditionMet() {
                return mockRestoreConsumer.position(changelogPartition) == 1L;
            }
        }, "Never restore first record");
        mockRestoreConsumer.setException(new InvalidOffsetException("Try Again!") {

            @Override
            public Set<TopicPartition> partitions() {
                return changelogPartitionSet;
            }
        });
        mockRestoreConsumer.addRecord(new ConsumerRecord<>("stream-thread-test-count-changelog", 0, 0L, "K1".getBytes(), "V1".getBytes()));
        mockRestoreConsumer.addRecord(new ConsumerRecord<>("stream-thread-test-count-changelog", 0, 1L, "K2".getBytes(), "V2".getBytes()));
        TestUtils.waitForCondition(new TestCondition() {

            @Override
            public boolean conditionMet() {
                mockRestoreConsumer.assign(changelogPartitionSet);
                return mockRestoreConsumer.position(changelogPartition) == 2L;
            }
        }, "Never finished restore");
    } finally {
        thread.shutdown();
        thread.join(10000);
    }
}
Also used : TaskId(org.apache.kafka.streams.processor.TaskId) Set(java.util.Set) HashSet(java.util.HashSet) HashMap(java.util.HashMap) InvalidOffsetException(org.apache.kafka.clients.consumer.InvalidOffsetException) Bytes(org.apache.kafka.common.utils.Bytes) TopicPartition(org.apache.kafka.common.TopicPartition) TestCondition(org.apache.kafka.test.TestCondition) PartitionInfo(org.apache.kafka.common.PartitionInfo) MockConsumer(org.apache.kafka.clients.consumer.MockConsumer) InternalStreamsBuilderTest(org.apache.kafka.streams.kstream.internals.InternalStreamsBuilderTest) Test(org.junit.Test)

Aggregations

InvalidOffsetException (org.apache.kafka.clients.consumer.InvalidOffsetException)6 Set (java.util.Set)5 Test (org.junit.Test)4 TopicPartition (org.apache.kafka.common.TopicPartition)3 ArrayList (java.util.ArrayList)2 HashMap (java.util.HashMap)2 HashSet (java.util.HashSet)2 TestCondition (org.apache.kafka.test.TestCondition)2 List (java.util.List)1 Map (java.util.Map)1 ConsumerRecord (org.apache.kafka.clients.consumer.ConsumerRecord)1 MockConsumer (org.apache.kafka.clients.consumer.MockConsumer)1 PartitionInfo (org.apache.kafka.common.PartitionInfo)1 Bytes (org.apache.kafka.common.utils.Bytes)1 KeyValue (org.apache.kafka.streams.KeyValue)1 StreamsException (org.apache.kafka.streams.errors.StreamsException)1 TaskMigratedException (org.apache.kafka.streams.errors.TaskMigratedException)1 InternalStreamsBuilderTest (org.apache.kafka.streams.kstream.internals.InternalStreamsBuilderTest)1 BatchingStateRestoreCallback (org.apache.kafka.streams.processor.BatchingStateRestoreCallback)1 TaskId (org.apache.kafka.streams.processor.TaskId)1