Vert.x does not provide exactly once semantics because exactly-once is very difficult to abstract in such an unopinionated framework and what "exactly once" means is dependent upon the application.
In reality, there's no such thing as exactly-once processing, there is only idempotence and through it exactly-once semantics. Systems that provide exactly once *semantics* do so through idempotence, and you can do the same. For instance, Storm's exactly once semantics are in reality achieved by processing and acking tuples in batches by storing resulting state in a persistent store. In the event of a replay of tuples, tuples in old batches will be ignored. But what's critical about how Storm provides exactly-once semantics is that it stores the metadata about batches with the data that results from those batches. That is, it stores the last batch processed with the resulting aggregate.
Similarly, Kafka's high level consumer batches messages and stores the highest offset processed by each consumer for each partition. But this does not achieve exactly-once semantics. If a consumer fails half way through processing a batch, the already processed messages will ultimately be replayed to some other consumer. If that consumer is non-deterministic (e.g. stores state in some external database) that can have detrimental effects. In order to achieve exactly-once processing, state has to be stored *with the last offset processed* for each processed message or batch of messages, otherwise there's some potential that the consumer can fail between storing the last processed offset and storing the output of the last processed offset.
So, that is to say that true exactly-once processing is a fantasy, and idempotence in the interest of exactly-once semantics is far too opinionated for Vert.x. But you can certainly create exactly-once semantics via idempotence on the Vert.x event bus, though it will require some coordination. Ultimately, the specific implementation is dependent on your application. At what point do exactly once semantics apply? Once the message is sent by a producer, or once it's received by a consumer? The basic pattern is this: publish messages from a producer with a timeout and tag messages with sequential identifiers. When a message is processed, store the last processed message with the result of that message in a fault-tolerant persistent store. If a message with a sequential ID lower than the last processed message is received, discard it. When a message is processed, ack it by replying to the producer. If a producer's send times out, resend the message with the same sequential ID. The idempotence of the consumer will ensure exactly-once semantics.
Even without batching messages, you should very easily be able to handle exactly once semantics for ~1000 messages/sec.