io.nats.client.BaseConsumeOptions Maven / Gradle / Ivy
// Copyright 2023 The NATS Authors
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at:
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package io.nats.client;
import io.nats.client.api.ConsumerConfiguration;
import io.nats.client.support.JsonParseException;
import io.nats.client.support.JsonParser;
import io.nats.client.support.JsonSerializable;
import io.nats.client.support.JsonValue;
import static io.nats.client.support.ApiConstants.*;
import static io.nats.client.support.JsonUtils.*;
import static io.nats.client.support.JsonValueUtils.readBoolean;
import static io.nats.client.support.JsonValueUtils.readInteger;
import static io.nats.client.support.JsonValueUtils.readLong;
/**
* Base Consume Options are provided to customize the way the consume and
* fetch operate. It is the base class for ConsumeOptions and FetchConsumeOptions.
*/
public class BaseConsumeOptions implements JsonSerializable {
public static final int DEFAULT_MESSAGE_COUNT = 500;
public static final int DEFAULT_MESSAGE_COUNT_WHEN_BYTES = 1_000_000;
public static final int DEFAULT_THRESHOLD_PERCENT = 25;
public static final long DEFAULT_EXPIRES_IN_MILLIS = 30000;
public static final long MIN_EXPIRES_MILLS = 1000;
public static final long MAX_HEARTBEAT_MILLIS = 30000;
public static final int MAX_IDLE_HEARTBEAT_PERCENT = 50;
protected final int messages;
protected final long bytes;
protected final long expiresIn;
protected final long idleHeartbeat;
protected final int thresholdPercent;
protected final boolean noWait;
@SuppressWarnings("rawtypes") // Don't need the type of the builder to get its vars
protected BaseConsumeOptions(Builder b) {
bytes = b.bytes;
if (bytes > 0) {
messages = b.messages == -1 ? DEFAULT_MESSAGE_COUNT_WHEN_BYTES : b.messages;
}
else {
messages = b.messages == -1 ? DEFAULT_MESSAGE_COUNT : b.messages;
}
// validation handled in builder
thresholdPercent = b.thresholdPercent;
noWait = b.noWait;
// if it's not noWait, it must have an expiresIn
// we can't check this in the builder because we can't guarantee order
// so we always default to LONG_UNSET in the builder and check it here.
if (b.expiresIn == ConsumerConfiguration.LONG_UNSET && !noWait) {
expiresIn = DEFAULT_EXPIRES_IN_MILLIS;
}
else {
expiresIn = b.expiresIn;
}
// calculated
idleHeartbeat = Math.min(MAX_HEARTBEAT_MILLIS, expiresIn * MAX_IDLE_HEARTBEAT_PERCENT / 100);
}
@Override
public String toJson() {
StringBuilder sb = beginJson();
addField(sb, MESSAGES, messages);
addField(sb, BYTES, bytes);
addField(sb, EXPIRES_IN, expiresIn);
addField(sb, IDLE_HEARTBEAT, idleHeartbeat);
addField(sb, THRESHOLD_PERCENT, thresholdPercent);
addFldWhenTrue(sb, NO_WAIT, noWait);
return endJson(sb).toString();
}
public long getExpiresInMillis() {
return expiresIn;
}
public long getIdleHeartbeat() {
return idleHeartbeat;
}
public int getThresholdPercent() {
return thresholdPercent;
}
public boolean isNoWait() {
return noWait;
}
protected static abstract class Builder {
protected int messages = -1;
protected long bytes = 0;
protected int thresholdPercent = DEFAULT_THRESHOLD_PERCENT;
protected long expiresIn = DEFAULT_EXPIRES_IN_MILLIS;
protected boolean noWait = false;
protected abstract B getThis();
protected B noWait() {
return getThis();
}
/**
* Initialize values from the json string.
* @param json the json string to parse
* @return the builder
* @throws JsonParseException if the json is invalid
*/
public B json(String json) throws JsonParseException {
return jsonValue(JsonParser.parse(json));
}
/**
* Initialize values from the JsonValue object.
* @param jsonValue the json value object
* @return the builder
*/
public B jsonValue(JsonValue jsonValue) {
messages(readInteger(jsonValue, MESSAGES, -1));
bytes(readLong(jsonValue, BYTES, -1));
expiresIn(readLong(jsonValue, EXPIRES_IN, MIN_EXPIRES_MILLS));
thresholdPercent(readInteger(jsonValue, THRESHOLD_PERCENT, -1));
if (readBoolean(jsonValue, NO_WAIT, false)) {
noWait();
}
return getThis();
}
protected B messages(int messages) {
this.messages = messages < 1 ? -1 : messages;
return getThis();
}
protected B bytes(long bytes) {
this.bytes = bytes < 1 ? 0 : bytes;
return getThis();
}
/**
* In Fetch, sets the maximum amount of time to wait to reach the batch size or max byte.
* In Consume, sets the maximum amount of time for an individual pull to be open
* before issuing a replacement pull.
* Zero or less will default to {@value BaseConsumeOptions#DEFAULT_EXPIRES_IN_MILLIS},
* otherwise, cannot be less than {@value BaseConsumeOptions#MIN_EXPIRES_MILLS}
* @param expiresInMillis the expiration time in milliseconds
* @return the builder
*/
public B expiresIn(long expiresInMillis) {
if (expiresInMillis < 1) { // this is way to clear or reset, just a code guard really
expiresIn = ConsumerConfiguration.LONG_UNSET;
}
else if (expiresInMillis < MIN_EXPIRES_MILLS) {
throw new IllegalArgumentException("Expires must be greater than or equal to " + MIN_EXPIRES_MILLS);
}
else {
expiresIn = expiresInMillis;
}
return getThis();
}
/**
* Set the threshold percent of max bytes (if max bytes is specified) or messages
* that will trigger issuing pull requests to keep messages flowing.
* Only applies to endless consumes.
* For instance if the batch size is 100 and the re-pull percent is 25,
* the first pull will be for 100, and then when 25 messages have been received
* another 75 will be requested, keeping the number of messages in transit always at 100.
* Must be between 1 and 100 inclusive.
* Less than 1 will assume the default of {@value BaseConsumeOptions#DEFAULT_THRESHOLD_PERCENT}.
* Greater than 100 will assume 100.
* @param thresholdPercent the threshold percent
* @return the builder
*/
public B thresholdPercent(int thresholdPercent) {
this.thresholdPercent = thresholdPercent < 1 ? DEFAULT_THRESHOLD_PERCENT : Math.min(100, thresholdPercent);
return getThis();
}
/**
* Build the options.
* @return the built options
*/
public abstract CO build();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy