All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.rabbitmq.stream.ConsumerFlowStrategy Maven / Gradle / Ivy

Go to download

The RabbitMQ Stream Java client library allows Java applications to interface with RabbitMQ Stream.

The newest version!
// Copyright (c) 2023 Broadcom. All Rights Reserved.
// The term "Broadcom" refers to Broadcom Inc. and/or its subsidiaries.
//
// This software, the RabbitMQ Stream Java client library, is dual-licensed under the
// Mozilla Public License 2.0 ("MPL"), and the Apache License version 2 ("ASL").
// For the MPL, please see LICENSE-MPL-RabbitMQ. For the ASL,
// please see LICENSE-APACHE2.
//
// This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND,
// either express or implied. See the LICENSE file for specific language governing
// rights and limitations of this software.
//
// If you have any questions regarding licensing, please contact us at
// [email protected].
package com.rabbitmq.stream;

import java.util.concurrent.atomic.AtomicLong;

/**
 * Contract to determine when a subscription provides credits to get more messages.
 *
 * 

The broker delivers "chunks" of messages to consumers. A chunk can contain from 1 to several * thousands of messages. The broker send chunks as long as the subscription has credits. A * client connection can provide credits for a given subscription and the broker will send the * corresponding number of chunks (1 credit = 1 chunk). * *

This credit mechanism avoids overwhelming a consumer with messages. A consumer does not want * to provide a credit only when it is done with messages of a chunk, because it will be idle * between its credit request and the arrival of the next chunk. The idea is to keep consumers busy * as much as possible, without accumulating an in-memory backlog on the client side. There is no * ideal solution, it depends on the use cases and several parameters (processing time, network, * etc). * *

This is an experimental API, subject to change. * * @since 0.12.0 * @see MessageHandler.Context#processed() * @see ConsumerBuilder#flow() */ public interface ConsumerFlowStrategy { /** * The initial number of credits for a subscription. * *

It must be greater than 0. Values are usually between 1 and 10. * * @return initial number of credits */ int initialCredits(); /** * Return the behavior for {@link MessageHandler.Context#processed()} calls. * *

This method is called for each chunk of messages. Implementations return a callback that * will be called when applications consider a message dealt with and call {@link * MessageHandler.Context#processed()}. The callback can count messages and provide credits * accordingly. * * @param context chunk context * @return the message processed callback */ MessageProcessedCallback start(Context context); /** Chunk context. */ interface Context { /** * Provide credits for the subscription. * *

{@link ConsumerFlowStrategy} implementation should always provide 1 credit a given chunk. * * @param credits the number of credits provided, usually 1 */ void credits(int credits); /** * The number of messages in the chunk. * * @return number of messages in the chunk */ long messageCount(); } /** Behavior for {@link MessageHandler.Context#processed()} calls. */ @FunctionalInterface interface MessageProcessedCallback { /** * Method called when {@link MessageHandler.Context#processed()} is called. * *

There is one instance of this class for a given chunk and it is called for the * processed() calls of the message of this chunk. * *

Implementations can count messages and call {@link Context#credits(int)} when appropriate. * *

Note calls to {@link MessageHandler.Context#processed()} are not idempotent: an * application can call the method several times for the same message and implementations must * deal with these multiple calls if they impact their logic. * * @param messageContext context of the message */ void processed(MessageHandler.Context messageContext); } /** * Strategy that provides 1 initial credit and a credit on each new chunk. * *

Calls to {@link MessageHandler.Context#processed()} are ignored. * * @return flow strategy */ static ConsumerFlowStrategy creditOnChunkArrival() { return creditOnChunkArrival(1); } /** * Strategy that provides the specified number of initial credits and a credit on each new chunk. * *

Calls to {@link MessageHandler.Context#processed()} are ignored. * * @param initialCredits number of initial credits * @return flow strategy */ static ConsumerFlowStrategy creditOnChunkArrival(int initialCredits) { return new CreditOnChunkArrivalConsumerFlowStrategy(initialCredits); } /** * Strategy that provides 1 initial credit and a credit when half of the chunk messages are * processed. * *

Make sure to call {@link MessageHandler.Context#processed()} on every message when using * this strategy, otherwise the broker may stop sending messages to the consumer. * * @return flow strategy */ static ConsumerFlowStrategy creditWhenHalfMessagesProcessed() { return creditOnProcessedMessageCount(1, 0.5); } /** * Strategy that provides the specified number of initial credits and a credit when half of the * chunk messages are processed. * *

Make sure to call {@link MessageHandler.Context#processed()} on every message when using * this strategy, otherwise the broker may stop sending messages to the consumer. * * @param initialCredits number of initial credits * @return flow strategy */ static ConsumerFlowStrategy creditWhenHalfMessagesProcessed(int initialCredits) { return creditOnProcessedMessageCount(initialCredits, 0.5); } /** * Strategy that provides the specified number of initial credits and a credit when the specified * ratio of the chunk messages are processed. * *

Make sure to call {@link MessageHandler.Context#processed()} on every message when using * this strategy, otherwise the broker may stop sending messages to the consumer. * * @param initialCredits number of initial credits * @return flow strategy */ static ConsumerFlowStrategy creditOnProcessedMessageCount(int initialCredits, double ratio) { return new MessageCountConsumerFlowStrategy(initialCredits, ratio); } /** * Strategy that provides the specified number of initial credits and a credit on each new chunk. * *

Calls to {@link MessageHandler.Context#processed()} are ignored. */ class CreditOnChunkArrivalConsumerFlowStrategy implements ConsumerFlowStrategy { private final int initialCredits; private CreditOnChunkArrivalConsumerFlowStrategy(int initialCredits) { this.initialCredits = initialCredits; } @Override public int initialCredits() { return this.initialCredits; } @Override public MessageProcessedCallback start(Context context) { context.credits(1); return value -> {}; } } /** * Strategy that provides the specified number of initial credits and a credit when the specified * ratio of the chunk messages are processed. * *

Make sure to call {@link MessageHandler.Context#processed()} on every message when using * this strategy, otherwise the broker may stop sending messages to the consumer. */ class MessageCountConsumerFlowStrategy implements ConsumerFlowStrategy { private final int initialCredits; private final double ratio; private MessageCountConsumerFlowStrategy(int initialCredits, double ratio) { this.initialCredits = initialCredits; this.ratio = ratio; } @Override public int initialCredits() { return this.initialCredits; } @Override public MessageProcessedCallback start(Context context) { long l = (long) (context.messageCount() * ratio); long limit = Math.max(1, l); AtomicLong processedMessages = new AtomicLong(0); return messageOffset -> { if (processedMessages.incrementAndGet() == limit) { context.credits(1); } }; } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy