Search in sources :

Example 1 with TopicPartitionResetResult

use of org.bf2.admin.kafka.admin.model.Types.TopicPartitionResetResult in project kafka-admin-api by bf2fc6cc711aee1a0c2a.

the class ConsumerGroupOperations method resetGroupOffset.

@SuppressWarnings({ "checkstyle:JavaNCSS", "checkstyle:MethodLength" })
public static CompletionStage<PagedResponse<TopicPartitionResetResult>> resetGroupOffset(KafkaAdminClient ac, Types.ConsumerGroupOffsetResetParameters parameters) {
    Promise<PagedResponse<TopicPartitionResetResult>> prom = Promise.promise();
    switch(parameters.getOffset()) {
        case EARLIEST:
        case LATEST:
            break;
        default:
            if (parameters.getValue() == null) {
                throw new InvalidRequestException("Value has to be set when " + parameters.getOffset().getValue() + " offset is used.");
            }
    }
    Set<TopicPartition> topicPartitionsToReset = new HashSet<>();
    // CompositeFuture#join requires raw type
    @SuppressWarnings("rawtypes") List<Future> promises = new ArrayList<>();
    if (parameters.getTopics() == null || parameters.getTopics().isEmpty()) {
        // reset everything
        Promise<Void> promise = Promise.promise();
        promises.add(promise.future());
        ac.listConsumerGroupOffsets(parameters.getGroupId()).onSuccess(consumerGroupOffsets -> {
            consumerGroupOffsets.entrySet().forEach(offset -> {
                topicPartitionsToReset.add(offset.getKey());
            });
            promise.complete();
        }).onFailure(promise::fail);
    } else {
        parameters.getTopics().forEach(paramPartition -> {
            Promise promise = Promise.promise();
            promises.add(promise.future());
            if (paramPartition.getPartitions() == null || paramPartition.getPartitions().isEmpty()) {
                ac.describeTopics(Collections.singletonList(paramPartition.getTopic())).compose(topicsDesc -> {
                    topicsDesc.entrySet().forEach(topicEntry -> {
                        topicsDesc.get(topicEntry.getKey()).getPartitions().forEach(partition -> {
                            topicPartitionsToReset.add(new TopicPartition(topicEntry.getKey(), partition.getPartition()));
                        });
                    });
                    promise.complete();
                    return Future.succeededFuture(topicPartitionsToReset);
                }).onFailure(promise::fail);
            } else {
                paramPartition.getPartitions().forEach(numPartition -> {
                    topicPartitionsToReset.add(new TopicPartition(paramPartition.getTopic(), numPartition));
                });
                promise.complete();
            }
        });
    }
    // get the set of partitions we want to reset
    CompositeFuture.join(promises).compose(i -> {
        if (i.failed()) {
            return Future.failedFuture(i.cause());
        } else {
            return Future.succeededFuture();
        }
    }).compose(nothing -> {
        return validatePartitionsResettable(ac, parameters.getGroupId(), topicPartitionsToReset);
    }).compose(nothing -> {
        Map<TopicPartition, OffsetSpec> partitionsToFetchOffset = new HashMap<>();
        topicPartitionsToReset.forEach(topicPartition -> {
            OffsetSpec offsetSpec;
            // absolute - just for the warning that set offset could be higher than latest
            switch(parameters.getOffset()) {
                case LATEST:
                    offsetSpec = OffsetSpec.LATEST;
                    break;
                case EARLIEST:
                    offsetSpec = OffsetSpec.EARLIEST;
                    break;
                case TIMESTAMP:
                    try {
                        offsetSpec = OffsetSpec.TIMESTAMP(ZonedDateTime.parse(parameters.getValue(), DATE_TIME_FORMATTER).toInstant().toEpochMilli());
                    } catch (DateTimeParseException e) {
                        throw new InvalidRequestException("Timestamp must be in format 'yyyy-MM-dd'T'HH:mm:ssz'" + e.getMessage());
                    }
                    break;
                case ABSOLUTE:
                    // we are checking whether offset is not negative (set behind latest)
                    offsetSpec = OffsetSpec.LATEST;
                    break;
                default:
                    throw new InvalidRequestException("Offset can be 'absolute', 'latest', 'earliest' or 'timestamp' only");
            }
            partitionsToFetchOffset.put(topicPartition, offsetSpec);
        });
        return Future.succeededFuture(partitionsToFetchOffset);
    }).compose(partitionsToFetchOffset -> {
        Promise<Map<TopicPartition, ListOffsetsResultInfo>> promise = Promise.promise();
        ac.listOffsets(partitionsToFetchOffset, partitionsOffsets -> {
            if (partitionsOffsets.failed()) {
                promise.fail(partitionsOffsets.cause());
                return;
            }
            if (parameters.getOffset() == OffsetType.ABSOLUTE) {
                // numeric offset provided; check whether x > latest
                promise.complete(partitionsOffsets.result().entrySet().stream().collect(Collectors.toMap(entry -> entry.getKey(), entry -> {
                    if (entry.getValue().getOffset() < Long.parseLong(parameters.getValue())) {
                        log.warnf("Selected offset %s is larger than latest %d", parameters.getValue(), entry.getValue().getOffset());
                    }
                    return new ListOffsetsResultInfo(Long.parseLong(parameters.getValue()), entry.getValue().getTimestamp(), entry.getValue().getLeaderEpoch());
                })));
            } else {
                Map<TopicPartition, ListOffsetsResultInfo> kokot = partitionsOffsets.result().entrySet().stream().collect(Collectors.toMap(entry -> entry.getKey(), entry -> new ListOffsetsResultInfo(partitionsOffsets.result().get(entry.getKey()).getOffset(), entry.getValue().getTimestamp(), entry.getValue().getLeaderEpoch())));
                promise.complete(kokot);
            }
        });
        return promise.future();
    }).compose(newOffsets -> {
        // assemble new offsets object
        Promise<Map<TopicPartition, OffsetAndMetadata>> promise = Promise.promise();
        ac.listConsumerGroupOffsets(parameters.getGroupId(), list -> {
            if (list.failed()) {
                promise.fail(list.cause());
                return;
            }
            if (list.result().isEmpty()) {
                promise.fail(new InvalidRequestException("Consumer Group " + parameters.getGroupId() + " does not consume any topics/partitions"));
                return;
            }
            promise.complete(newOffsets.entrySet().stream().collect(Collectors.toMap(entry -> entry.getKey(), entry -> new OffsetAndMetadata(newOffsets.get(entry.getKey()).getOffset(), list.result().get(entry.getKey()) == null ? null : list.result().get(entry.getKey()).getMetadata()))));
        });
        return promise.future();
    }).compose(newOffsets -> {
        Promise<Void> promise = Promise.promise();
        ac.alterConsumerGroupOffsets(parameters.getGroupId(), newOffsets, res -> {
            if (res.failed()) {
                promise.fail(res.cause());
                return;
            }
            promise.complete();
            log.info("resetting offsets");
        });
        return promise.future();
    }).compose(i -> {
        Promise<Types.PagedResponse<Types.TopicPartitionResetResult>> promise = Promise.promise();
        ac.listConsumerGroupOffsets(parameters.getGroupId(), res -> {
            if (res.failed()) {
                promise.fail(res.cause());
                return;
            }
            var result = res.result().entrySet().stream().map(entry -> {
                Types.TopicPartitionResetResult reset = new Types.TopicPartitionResetResult();
                reset.setTopic(entry.getKey().getTopic());
                reset.setPartition(entry.getKey().getPartition());
                reset.setOffset(entry.getValue().getOffset());
                return reset;
            }).collect(Collectors.toList());
            Types.PagedResponse.forItems(result).onSuccess(promise::complete).onFailure(promise::fail);
        });
        return promise.future();
    }).onComplete(res -> {
        if (res.succeeded()) {
            prom.complete(res.result());
        } else {
            prom.fail(res.cause());
        }
        ac.close();
    });
    return prom.future().toCompletionStage();
}
Also used : CommonHandler(org.bf2.admin.kafka.admin.handlers.CommonHandler) Logger(org.jboss.logging.Logger) ZonedDateTime(java.time.ZonedDateTime) HashMap(java.util.HashMap) Function(java.util.function.Function) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) CompositeFuture(io.vertx.core.CompositeFuture) ConsumerGroupDescription(io.vertx.kafka.admin.ConsumerGroupDescription) ConsumerGroupListing(io.vertx.kafka.admin.ConsumerGroupListing) TopicPartitionResetResult(org.bf2.admin.kafka.admin.model.Types.TopicPartitionResetResult) Map(java.util.Map) PagedResponse(org.bf2.admin.kafka.admin.model.Types.PagedResponse) MemberDescription(io.vertx.kafka.admin.MemberDescription) ToLongFunction(java.util.function.ToLongFunction) ListOffsetsResultInfo(io.vertx.kafka.admin.ListOffsetsResultInfo) Promise(io.vertx.core.Promise) OffsetAndMetadata(io.vertx.kafka.client.consumer.OffsetAndMetadata) Collection(java.util.Collection) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) Set(java.util.Set) Future(io.vertx.core.Future) Collectors(java.util.stream.Collectors) TopicPartition(io.vertx.kafka.client.common.TopicPartition) Objects(java.util.Objects) GroupIdNotFoundException(org.apache.kafka.common.errors.GroupIdNotFoundException) OffsetType(org.bf2.admin.kafka.admin.model.Types.ConsumerGroupOffsetResetParameters.OffsetType) DateTimeParseException(java.time.format.DateTimeParseException) List(java.util.List) CompletionStage(java.util.concurrent.CompletionStage) Stream(java.util.stream.Stream) PagedResponseDeprecated(org.bf2.admin.kafka.admin.model.Types.PagedResponseDeprecated) DateTimeFormatter(java.time.format.DateTimeFormatter) ConsumerGroupState(org.apache.kafka.common.ConsumerGroupState) UnknownTopicOrPartitionException(org.apache.kafka.common.errors.UnknownTopicOrPartitionException) InvalidRequestException(org.apache.kafka.common.errors.InvalidRequestException) Pattern(java.util.regex.Pattern) Comparator(java.util.Comparator) Types(org.bf2.admin.kafka.admin.model.Types) Collections(java.util.Collections) KafkaAdminClient(io.vertx.kafka.admin.KafkaAdminClient) OffsetSpec(io.vertx.kafka.admin.OffsetSpec) Types(org.bf2.admin.kafka.admin.model.Types) TopicPartitionResetResult(org.bf2.admin.kafka.admin.model.Types.TopicPartitionResetResult) ListOffsetsResultInfo(io.vertx.kafka.admin.ListOffsetsResultInfo) ArrayList(java.util.ArrayList) TopicPartitionResetResult(org.bf2.admin.kafka.admin.model.Types.TopicPartitionResetResult) OffsetAndMetadata(io.vertx.kafka.client.consumer.OffsetAndMetadata) InvalidRequestException(org.apache.kafka.common.errors.InvalidRequestException) HashSet(java.util.HashSet) Promise(io.vertx.core.Promise) DateTimeParseException(java.time.format.DateTimeParseException) TopicPartition(io.vertx.kafka.client.common.TopicPartition) OffsetSpec(io.vertx.kafka.admin.OffsetSpec) CompositeFuture(io.vertx.core.CompositeFuture) Future(io.vertx.core.Future) PagedResponse(org.bf2.admin.kafka.admin.model.Types.PagedResponse) HashMap(java.util.HashMap) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap)

Aggregations

CompositeFuture (io.vertx.core.CompositeFuture)1 Future (io.vertx.core.Future)1 Promise (io.vertx.core.Promise)1 ConsumerGroupDescription (io.vertx.kafka.admin.ConsumerGroupDescription)1 ConsumerGroupListing (io.vertx.kafka.admin.ConsumerGroupListing)1 KafkaAdminClient (io.vertx.kafka.admin.KafkaAdminClient)1 ListOffsetsResultInfo (io.vertx.kafka.admin.ListOffsetsResultInfo)1 MemberDescription (io.vertx.kafka.admin.MemberDescription)1 OffsetSpec (io.vertx.kafka.admin.OffsetSpec)1 TopicPartition (io.vertx.kafka.client.common.TopicPartition)1 OffsetAndMetadata (io.vertx.kafka.client.consumer.OffsetAndMetadata)1 ZonedDateTime (java.time.ZonedDateTime)1 DateTimeFormatter (java.time.format.DateTimeFormatter)1 DateTimeParseException (java.time.format.DateTimeParseException)1 ArrayList (java.util.ArrayList)1 Collection (java.util.Collection)1 Collections (java.util.Collections)1 Comparator (java.util.Comparator)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1