io.rsocket.core.Resume Maven / Gradle / Ivy
Show all versions of rsocket-core Show documentation
/*
* Copyright 2015-2020 the original author or 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
*
* https://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.rsocket.core;
import io.netty.buffer.ByteBuf;
import io.rsocket.frame.ResumeFrameCodec;
import io.rsocket.resume.InMemoryResumableFramesStore;
import io.rsocket.resume.ResumableFramesStore;
import java.time.Duration;
import java.util.Objects;
import java.util.function.Function;
import java.util.function.Supplier;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import reactor.util.retry.Retry;
/**
* Simple holder of configuration settings for the RSocket Resume capability. This can be used to
* configure an {@link RSocketConnector} or an {@link RSocketServer} except for {@link
* #retry(Retry)} and {@link #token(Supplier)} which apply only to the client side.
*/
public class Resume {
private static final Logger logger = LoggerFactory.getLogger(Resume.class);
private Duration sessionDuration = Duration.ofMinutes(2);
/* Storage */
private boolean cleanupStoreOnKeepAlive;
private Function super ByteBuf, ? extends ResumableFramesStore> storeFactory;
private Duration streamTimeout = Duration.ofSeconds(10);
/* Client only */
private Supplier tokenSupplier = ResumeFrameCodec::generateResumeToken;
private Retry retry =
Retry.backoff(Long.MAX_VALUE, Duration.ofSeconds(1))
.maxBackoff(Duration.ofSeconds(16))
.jitter(1.0)
.doBeforeRetry(signal -> logger.debug("Connection error", signal.failure()));
public Resume() {}
/**
* The maximum time for a client to keep trying to reconnect. During this time client and server
* continue to store unsent frames to keep the session warm and ready to resume.
*
* By default this is set to 2 minutes.
*
* @param sessionDuration the max duration for a session
* @return the same instance for method chaining
*/
public Resume sessionDuration(Duration sessionDuration) {
this.sessionDuration = Objects.requireNonNull(sessionDuration);
return this;
}
/**
* When this property is enabled, hints from {@code KEEPALIVE} frames about how much data has been
* received by the other side, is used to proactively clean frames from the {@link
* #storeFactory(Function) store}.
*
*
By default this is set to {@code false} in which case information from {@code KEEPALIVE} is
* ignored and old frames from the store are removed only when the store runs out of space.
*
* @return the same instance for method chaining
*/
public Resume cleanupStoreOnKeepAlive() {
this.cleanupStoreOnKeepAlive = true;
return this;
}
/**
* Configure a factory to create the storage for buffering (or persisting) a window of frames that
* may need to be sent again to resume after a dropped connection.
*
*
By default {@link InMemoryResumableFramesStore} is used with its cache size set to 100,000
* bytes. When the cache fills up, the oldest frames are gradually removed to create space for new
* ones.
*
* @param storeFactory the factory to use to create the store
* @return the same instance for method chaining
*/
public Resume storeFactory(
Function super ByteBuf, ? extends ResumableFramesStore> storeFactory) {
this.storeFactory = storeFactory;
return this;
}
/**
* A {@link reactor.core.publisher.Flux#timeout(Duration) timeout} value to apply to the resumed
* session stream obtained from the {@link #storeFactory(Function) store} after a reconnect. The
* resume stream must not take longer than the specified time to emit each frame.
*
*
By default this is set to 10 seconds.
*
* @param streamTimeout the timeout value for resuming a session stream
* @return the same instance for method chaining
*/
public Resume streamTimeout(Duration streamTimeout) {
this.streamTimeout = Objects.requireNonNull(streamTimeout);
return this;
}
/**
* Configure the logic for reconnecting. This setting is for use with {@link
* RSocketConnector#resume(Resume)} on the client side only.
*
*
By default this is set to:
*
*
{@code
* Retry.backoff(Long.MAX_VALUE, Duration.ofSeconds(1))
* .maxBackoff(Duration.ofSeconds(16))
* .jitter(1.0)
* }
*
* @param retry the {@code Retry} spec to use when attempting to reconnect
* @return the same instance for method chaining
*/
public Resume retry(Retry retry) {
this.retry = retry;
return this;
}
/**
* Customize the generation of the resume identification token used to resume. This setting is for
* use with {@link RSocketConnector#resume(Resume)} on the client side only.
*
* By default this is {@code ResumeFrameFlyweight::generateResumeToken}.
*
* @param supplier a custom generator for a resume identification token
* @return the same instance for method chaining
*/
public Resume token(Supplier supplier) {
this.tokenSupplier = supplier;
return this;
}
// Package private accessors
Duration getSessionDuration() {
return sessionDuration;
}
boolean isCleanupStoreOnKeepAlive() {
return cleanupStoreOnKeepAlive;
}
Function super ByteBuf, ? extends ResumableFramesStore> getStoreFactory(String tag) {
return storeFactory != null
? storeFactory
: token -> new InMemoryResumableFramesStore(tag, token, 100_000);
}
Duration getStreamTimeout() {
return streamTimeout;
}
Retry getRetry() {
return retry;
}
Supplier getTokenSupplier() {
return tokenSupplier;
}
}