use of org.bf2.admin.kafka.admin.model.Types.PagedResponse 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();
}
Aggregations