Skip to content

Commit

Permalink
Provide VoidOutput for Fire&Forget command usage #1529
Browse files Browse the repository at this point in the history
We now provide a VoidOutput that can be used for Fire&Forget use of Redis Commands.
  • Loading branch information
mp911de committed Nov 27, 2020
1 parent 85e91af commit cf2e6e5
Show file tree
Hide file tree
Showing 3 changed files with 163 additions and 55 deletions.
50 changes: 0 additions & 50 deletions src/main/java/io/lettuce/core/dynamic/output/VoidOutput.java

This file was deleted.

135 changes: 135 additions & 0 deletions src/main/java/io/lettuce/core/output/VoidOutput.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,135 @@
/*
* Copyright 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.lettuce.core.output;

import java.nio.ByteBuffer;

import io.lettuce.core.codec.RedisCodec;

/**
* {@link Void} command output to consume data silently without actually processing it. Creating {@link VoidCodec} through its
* constructor will preserve its error decoding since decoding errors is stateful. Obtaining {@link VoidOutput} through
* {@link #create()} will return an instance that does not decode errors.
*
* @param <K> Key type.
* @param <V> Value type.
* @author Mark Paluch
* @since 6.0.2
*/
public class VoidOutput<K, V> extends CommandOutput<K, V, Void> {

private static final VoidOutput<Void, Void> INSTANCE = new VoidOutput<Void, Void>(VoidCodec.INSTANCE) {

@Override
public void setError(String error) {
// no-op
}

@Override
public void setError(ByteBuffer error) {
// no-op
}

};

/**
* Initialize a new instance that decodes errors.
*/
@SuppressWarnings("unchecked")
public VoidOutput() {
this((RedisCodec<K, V>) VoidCodec.INSTANCE);
}

/**
* Initialize a new instance that decodes errors.
*
* @param codec used for type inference, must not be {@code null}.
*/
public VoidOutput(RedisCodec<K, V> codec) {
super(codec, null);
}

/**
* Returns an instance of {@link VoidOutput} coerced to the expected generics. Since this codec does not decode any data at
* all, it's safe to use this way. Note that this method is only suitable for fire-and-forget usage since errors are not
* decoded.
*
* @param <K> Key type.
* @param <V> Value type.
* @return the {@link VoidOutput} instance.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
public static <K, V> VoidOutput<K, V> create() {
return (VoidOutput) INSTANCE;
}

@Override
public void set(ByteBuffer bytes) {
// no-op
}

@Override
public void set(long integer) {
// no-op
}

@Override
public void setSingle(ByteBuffer bytes) {
// no-op
}

@Override
public void setBigNumber(ByteBuffer bytes) {
// no-op
}

@Override
public void set(double number) {
// no-op
}

@Override
public void set(boolean value) {
// no-op
}

enum VoidCodec implements RedisCodec<Void, Void> {

INSTANCE;

@Override
public Void decodeKey(ByteBuffer bytes) {
return null;
}

@Override
public Void decodeValue(ByteBuffer bytes) {
return null;
}

@Override
public ByteBuffer encodeKey(Void key) {
return null;
}

@Override
public ByteBuffer encodeValue(Void value) {
return null;
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,8 @@
*/
package io.lettuce.core.commands;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
import static org.assertj.core.api.Assertions.*;
import static org.junit.jupiter.api.Assumptions.*;

import java.util.Arrays;

Expand All @@ -35,11 +34,19 @@
import io.lettuce.core.api.sync.RedisCommands;
import io.lettuce.core.codec.StringCodec;
import io.lettuce.core.output.StatusOutput;
import io.lettuce.core.protocol.*;
import io.lettuce.test.TestFutures;
import io.lettuce.core.output.VoidOutput;
import io.lettuce.core.protocol.AsyncCommand;
import io.lettuce.core.protocol.Command;
import io.lettuce.core.protocol.CommandArgs;
import io.lettuce.core.protocol.CommandType;
import io.lettuce.core.protocol.ProtocolKeyword;
import io.lettuce.core.protocol.RedisCommand;
import io.lettuce.test.LettuceExtension;
import io.lettuce.test.TestFutures;

/**
* Integration tests for {@link RedisCommands#dispatch}.
*
* @author Mark Paluch
*/
@ExtendWith(LettuceExtension.class)
Expand Down Expand Up @@ -75,6 +82,22 @@ void dispatchWithoutArgs() {
assertThat(response).contains("connected_clients");
}

@Test
void dispatchFireAndForget() {
redis.set(key, value);
redis.dispatch(CommandType.LLEN, VoidOutput.create(), new CommandArgs<>(StringCodec.UTF8).addKey(key));
}

@Test
void dispatchNoOutputButError() {

redis.set(key, value);

assertThatExceptionOfType(RedisCommandExecutionException.class).isThrownBy(
() -> redis.dispatch(CommandType.LLEN, new VoidOutput<>(), new CommandArgs<>(StringCodec.UTF8).addKey(key)))
.withMessageStartingWith("WRONGTYPE");
}

@Test
void dispatchShouldFailForWrongDataType() {

Expand Down

0 comments on commit cf2e6e5

Please sign in to comment.