This is an automated email from the ASF dual-hosted git repository.
chenguangsheng pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-eventmesh.git
The following commit(s) were added to refs/heads/master by this push:
new 670867656 [ISSUE #3370] Add eventmesh-storage-redis module
new d5c97e819 Merge pull request #3371 from xwm1992/add-storage-redis
670867656 is described below
commit 670867656102cf902635056b714f0bbfbc80e41d
Author: xwm1992 <[email protected]>
AuthorDate: Wed Mar 8 20:11:45 2023 +0800
[ISSUE #3370] Add eventmesh-storage-redis module
---
.../eventmesh-storage-redis/build.gradle | 56 +++++++++
.../eventmesh-storage-redis/gradle.properties | 18 +++
.../storage/redis/client/RedissonClient.java | 114 +++++++++++++++++
.../storage/redis/cloudevent/CloudEventCodec.java | 60 +++++++++
.../storage/redis/config/RedisProperties.java | 66 ++++++++++
.../storage/redis/consumer/RedisConsumer.java | 131 +++++++++++++++++++
.../storage/redis/producer/RedisProducer.java | 139 +++++++++++++++++++++
.../redis/storage/RedisStorageResourceService.java | 33 +++++
.../org.apache.eventmesh.api.consumer.Consumer | 16 +++
.../org.apache.eventmesh.api.producer.Producer | 16 +++
...he.eventmesh.api.storage.StorageResourceService | 16 +++
.../src/main/resources/redis-client.properties | 17 +++
.../storage/redis/AbstractRedisServer.java | 41 ++++++
.../storage/redis/client/RedissonClientTest.java | 31 +++++
.../storage/redis/config/RedisPropertiesTest.java | 47 +++++++
.../storage/redis/connector/UnitTest.java | 110 ++++++++++++++++
.../storage/redis/consumer/RedisConsumerTest.java | 91 ++++++++++++++
.../storage/redis/producer/RedisProducerTest.java | 110 ++++++++++++++++
.../src/test/resources/redis-client.properties | 21 ++++
19 files changed, 1133 insertions(+)
diff --git a/eventmesh-storage/eventmesh-storage-redis/build.gradle
b/eventmesh-storage/eventmesh-storage-redis/build.gradle
new file mode 100644
index 000000000..b681d7cff
--- /dev/null
+++ b/eventmesh-storage/eventmesh-storage-redis/build.gradle
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.
+ */
+
+configurations {
+ implementation.exclude group: 'org.slf4j', module: 'slf4j-simple'
+}
+
+dependencies {
+ implementation project(":eventmesh-common")
+ implementation project(":eventmesh-storage:eventmesh-storage-api")
+
+ // redisson
+ implementation('org.redisson:redisson:3.17.3') {
+ exclude group: 'io.netty', module: 'netty-common'
+ exclude group: 'io.netty', module: 'netty-buffer'
+ exclude group: 'io.netty', module: 'netty-codec'
+ exclude group: 'io.netty', module: 'netty-transport'
+ exclude group: 'io.netty', module: 'netty-resolver'
+ exclude group: 'io.netty', module: 'netty-resolver-dns'
+ exclude group: 'io.netty', module: 'netty-handler'
+ }
+
+ // netty
+ implementation "io.netty:netty-all"
+
+ // auxiliary serialize
+ api 'io.cloudevents:cloudevents-json-jackson'
+
+ // test dependencies
+ testImplementation 'ai.grakn:redis-mock:0.1.6'
+ testImplementation "org.mockito:mockito-core"
+
+ compileOnly 'org.projectlombok:lombok'
+ annotationProcessor 'org.projectlombok:lombok'
+
+ testCompileOnly 'org.projectlombok:lombok'
+ testAnnotationProcessor 'org.projectlombok:lombok'
+}
+
+test {
+ systemProperty "io.netty.tryUnsafe", "false"
+}
diff --git a/eventmesh-storage/eventmesh-storage-redis/gradle.properties
b/eventmesh-storage/eventmesh-storage-redis/gradle.properties
new file mode 100644
index 000000000..899c915a5
--- /dev/null
+++ b/eventmesh-storage/eventmesh-storage-redis/gradle.properties
@@ -0,0 +1,18 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+
+pluginType=storage
+pluginName=redis
\ No newline at end of file
diff --git
a/eventmesh-storage/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/client/RedissonClient.java
b/eventmesh-storage/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/client/RedissonClient.java
new file mode 100644
index 000000000..43f4181e4
--- /dev/null
+++
b/eventmesh-storage/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/client/RedissonClient.java
@@ -0,0 +1,114 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.eventmesh.storage.redis.client;
+
+import org.apache.eventmesh.api.exception.StorageConnectorRuntimeException;
+import org.apache.eventmesh.common.Constants;
+import org.apache.eventmesh.common.config.ConfigService;
+import org.apache.eventmesh.storage.redis.cloudevent.CloudEventCodec;
+import org.apache.eventmesh.storage.redis.config.RedisProperties;
+
+import java.util.Arrays;
+
+import org.redisson.Redisson;
+import org.redisson.config.Config;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.databind.SerializationFeature;
+
+/**
+ * Within EventMesh's JVM, there is no multi-connector server, and redisson
itself is pooled management, so a single instance is fine, and it can save
+ * resources and improve performance.
+ */
+public final class RedissonClient {
+
+ private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
+
+ public static final Redisson INSTANCE;
+
+ static {
+ OBJECT_MAPPER.configure(SerializationFeature.FAIL_ON_EMPTY_BEANS,
false);
+
+ INSTANCE = create();
+
+ Runtime.getRuntime().addShutdownHook(new Thread(() -> {
+ try {
+ INSTANCE.shutdown();
+ } catch (Exception ignore) {
+ //
+ }
+ }));
+ }
+
+ public static Redisson create() {
+ ConfigService configService = ConfigService.getInstance();
+ RedisProperties properties =
configService.buildConfigInstance(RedisProperties.class);
+
+ return create(properties);
+ }
+
+ private static Redisson create(RedisProperties properties) {
+ RedisProperties.ServerType serverType;
+ try {
+ serverType = properties.getServerType();
+ } catch (IllegalArgumentException ie) {
+ final String message = "Invalid Redis server type: " +
properties.getServerType()
+ + ", supported values are: "
+ + Arrays.toString(RedisProperties.ServerType.values());
+ throw new StorageConnectorRuntimeException(message, ie);
+ }
+
+ String serverAddress = properties.getServerAddress();
+ String serverPassword = properties.getServerPassword();
+ String masterName = properties.getServerMasterName();
+
+ Config config =
OBJECT_MAPPER.convertValue(properties.getRedissonProperties(), Config.class);
+
+ if (config == null) {
+ config = new Config();
+ }
+
+ config.setCodec(CloudEventCodec.INSTANCE);
+
+ switch (serverType) {
+ case SINGLE:
+ config.useSingleServer()
+ .setAddress(serverAddress)
+ .setPassword(serverPassword);
+ break;
+ case CLUSTER:
+ config.useClusterServers()
+ .addNodeAddress(serverAddress.split(Constants.COMMA))
+ .setPassword(serverPassword);
+ break;
+ case SENTINEL:
+ config.useSentinelServers()
+ .setMasterName(masterName)
+ .addSentinelAddress(serverAddress)
+ .setPassword(serverPassword);
+ break;
+ default:
+ final String message = "Invalid Redis server type: " +
properties.getServerType()
+ + ", supported values are: "
+ + Arrays.toString(RedisProperties.ServerType.values());
+ throw new StorageConnectorRuntimeException(message);
+ }
+
+ return (Redisson) Redisson.create(config);
+ }
+}
diff --git
a/eventmesh-storage/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/cloudevent/CloudEventCodec.java
b/eventmesh-storage/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/cloudevent/CloudEventCodec.java
new file mode 100644
index 000000000..932488d8c
--- /dev/null
+++
b/eventmesh-storage/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/cloudevent/CloudEventCodec.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.eventmesh.storage.redis.cloudevent;
+
+import org.redisson.client.codec.BaseCodec;
+import org.redisson.client.protocol.Decoder;
+import org.redisson.client.protocol.Encoder;
+
+import io.cloudevents.CloudEvent;
+import io.cloudevents.jackson.JsonFormat;
+import io.netty.buffer.ByteBuf;
+import io.netty.buffer.ByteBufAllocator;
+
+
+public class CloudEventCodec extends BaseCodec {
+
+ public static final CloudEventCodec INSTANCE = new CloudEventCodec();
+
+ private static final JsonFormat jsonFormat = new JsonFormat(false, true);
+
+ private static final Encoder encoder = in -> {
+ ByteBuf out = ByteBufAllocator.DEFAULT.buffer();
+ if (in instanceof CloudEvent) {
+ out.writeBytes(jsonFormat.serialize((CloudEvent) in));
+ return out;
+ }
+ throw new IllegalStateException("Illegal object type: " +
in.getClass().getSimpleName());
+ };
+
+ private static final Decoder<Object> decoder = (buf, state) -> {
+ final byte[] bytes = new byte[buf.readableBytes()];
+ buf.getBytes(buf.readerIndex(), bytes);
+ return jsonFormat.deserialize(bytes);
+ };
+
+ @Override
+ public Decoder<Object> getValueDecoder() {
+ return decoder;
+ }
+
+ @Override
+ public Encoder getValueEncoder() {
+ return encoder;
+ }
+}
diff --git
a/eventmesh-storage/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/config/RedisProperties.java
b/eventmesh-storage/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/config/RedisProperties.java
new file mode 100644
index 000000000..9ac97b1db
--- /dev/null
+++
b/eventmesh-storage/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/config/RedisProperties.java
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.eventmesh.storage.redis.config;
+
+import org.apache.eventmesh.common.config.Config;
+import org.apache.eventmesh.common.config.ConfigFiled;
+
+import java.util.Properties;
+
+import lombok.Data;
+
+@Data
+@Config(prefix = "eventMesh.server.redis", path =
"classPath://redis-client.properties")
+public class RedisProperties {
+
+ /**
+ * The redis server configuration to be used.
+ */
+ @ConfigFiled(field = "serverType")
+ private ServerType serverType = ServerType.SINGLE;
+
+ /**
+ * The master server name used by Redis Sentinel servers and master change
monitoring task.
+ */
+ @ConfigFiled(field = "serverMasterName")
+ private String serverMasterName = "master";
+
+ /**
+ * The address of the redis server following format --
host1:port1,host2:port2,……
+ */
+ @ConfigFiled(field = "serverAddress")
+ private String serverAddress;
+
+ /**
+ * The password for redis authentication.
+ */
+ @ConfigFiled(field = "serverPassword")
+ private String serverPassword;
+
+ /**
+ * The redisson options, redisson properties prefix is
`eventMesh.server.redis.redisson`
+ */
+ @ConfigFiled(field = "redisson")
+ private Properties redissonProperties;
+
+ public enum ServerType {
+ SINGLE,
+ CLUSTER,
+ SENTINEL
+ }
+}
diff --git
a/eventmesh-storage/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/consumer/RedisConsumer.java
b/eventmesh-storage/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/consumer/RedisConsumer.java
new file mode 100644
index 000000000..5d689fe96
--- /dev/null
+++
b/eventmesh-storage/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/consumer/RedisConsumer.java
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.eventmesh.storage.redis.consumer;
+
+import org.apache.eventmesh.api.AbstractContext;
+import org.apache.eventmesh.api.EventListener;
+import org.apache.eventmesh.api.EventMeshAction;
+import org.apache.eventmesh.api.EventMeshAsyncConsumeContext;
+import org.apache.eventmesh.api.consumer.Consumer;
+import org.apache.eventmesh.storage.redis.client.RedissonClient;
+
+import java.util.List;
+import java.util.Properties;
+
+import org.redisson.Redisson;
+import org.redisson.api.listener.MessageListener;
+
+import io.cloudevents.CloudEvent;
+
+import com.google.common.base.Preconditions;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class RedisConsumer implements Consumer {
+
+
+ private Redisson redisson;
+
+ private EventMeshMessageListener messageListener;
+
+ private volatile boolean started = false;
+
+ @Override
+ public boolean isStarted() {
+ return started;
+ }
+
+ @Override
+ public boolean isClosed() {
+ return !isStarted();
+ }
+
+ @Override
+ public synchronized void start() {
+ if (!started) {
+ started = true;
+ }
+ }
+
+ @Override
+ public synchronized void shutdown() {
+ if (started) {
+ redisson = null;
+ messageListener = null;
+ started = false;
+ }
+ }
+
+ @Override
+ public void init(Properties keyValue) {
+ // Currently, 'keyValue' does not pass useful configuration
information.
+ redisson = RedissonClient.INSTANCE;
+ }
+
+ @Override
+ public void updateOffset(List<CloudEvent> cloudEvents, AbstractContext
context) {
+
+ }
+
+ @Override
+ public void subscribe(String topic) {
+ Preconditions.checkNotNull(topic);
+ Preconditions.checkNotNull(messageListener);
+
+ redisson.getTopic(topic).addListenerAsync(CloudEvent.class,
messageListener);
+ }
+
+ @Override
+ public void unsubscribe(String topic) {
+ Preconditions.checkNotNull(topic);
+ Preconditions.checkNotNull(messageListener);
+
+ redisson.getTopic(topic).removeListenerAsync(messageListener);
+ }
+
+ @Override
+ public void registerEventListener(EventListener listener) {
+ Preconditions.checkNotNull(listener);
+
+ messageListener = new EventMeshMessageListener(listener);
+ }
+
+ static class EventMeshMessageListener implements
MessageListener<CloudEvent> {
+
+ private final EventListener listener;
+
+ EventMeshMessageListener(EventListener listener) {
+ this.listener = listener;
+ }
+
+ @Override
+ public void onMessage(CharSequence channel, CloudEvent msg) {
+
+ final EventMeshAsyncConsumeContext consumeContext = new
EventMeshAsyncConsumeContext() {
+ @Override
+ public void commit(EventMeshAction action) {
+ log.info("channel: {} consumer event: {} finish action:
{}",
+ channel, msg.getId(), action);
+ }
+ };
+
+ listener.consume(msg, consumeContext);
+ }
+ }
+}
diff --git
a/eventmesh-storage/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/producer/RedisProducer.java
b/eventmesh-storage/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/producer/RedisProducer.java
new file mode 100644
index 000000000..329307f41
--- /dev/null
+++
b/eventmesh-storage/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/producer/RedisProducer.java
@@ -0,0 +1,139 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.eventmesh.storage.redis.producer;
+
+import org.apache.eventmesh.api.RequestReplyCallback;
+import org.apache.eventmesh.api.SendCallback;
+import org.apache.eventmesh.api.SendResult;
+import org.apache.eventmesh.api.exception.OnExceptionContext;
+import org.apache.eventmesh.api.exception.StorageConnectorRuntimeException;
+import org.apache.eventmesh.api.producer.Producer;
+import org.apache.eventmesh.storage.redis.client.RedissonClient;
+
+import java.util.Properties;
+
+import org.redisson.Redisson;
+import org.redisson.api.RTopic;
+
+import io.cloudevents.CloudEvent;
+
+import com.google.common.base.Preconditions;
+
+public class RedisProducer implements Producer {
+
+ private Redisson redisson;
+
+ private volatile boolean started = false;
+
+ @Override
+ public boolean isStarted() {
+ return started;
+ }
+
+ @Override
+ public boolean isClosed() {
+ return !isStarted();
+ }
+
+ @Override
+ public synchronized void start() {
+ if (!started) {
+ started = true;
+ }
+ }
+
+ @Override
+ public synchronized void shutdown() {
+ if (started) {
+ try {
+ redisson = null;
+ } finally {
+ started = false;
+ }
+ }
+ }
+
+ @Override
+ public void init(Properties properties) {
+ // Currently, 'properties' does not pass useful configuration
information.
+ redisson = RedissonClient.INSTANCE;
+ }
+
+ @Override
+ public void publish(CloudEvent cloudEvent, SendCallback sendCallback) {
+ Preconditions.checkNotNull(cloudEvent);
+ Preconditions.checkNotNull(sendCallback);
+
+ try {
+ RTopic topic = redisson.getTopic(cloudEvent.getSubject());
+
+ topic.publishAsync(cloudEvent).whenCompleteAsync((stage,
throwable) -> {
+ if (throwable != null) {
+ sendCallback.onException(
+ OnExceptionContext.builder()
+ .topic(cloudEvent.getSubject())
+ .messageId(cloudEvent.getId())
+ .exception(new
StorageConnectorRuntimeException(throwable))
+ .build()
+ );
+ } else {
+ SendResult sendResult = new SendResult();
+ sendResult.setTopic(cloudEvent.getSubject());
+ sendResult.setMessageId(cloudEvent.getId());
+ sendCallback.onSuccess(sendResult);
+ }
+ });
+ } catch (Exception e) {
+ sendCallback.onException(
+ OnExceptionContext.builder()
+ .topic(cloudEvent.getSubject())
+ .messageId(cloudEvent.getId())
+ .exception(new StorageConnectorRuntimeException(e))
+ .build()
+ );
+ }
+ }
+
+ @Override
+ public void sendOneway(CloudEvent cloudEvent) {
+ Preconditions.checkNotNull(cloudEvent);
+
+ RTopic topic = redisson.getTopic(cloudEvent.getSubject());
+ topic.publish(cloudEvent);
+ }
+
+ @Override
+ public void request(CloudEvent cloudEvent, RequestReplyCallback
rrCallback, long timeout) {
+ throw new StorageConnectorRuntimeException("Request is not supported");
+ }
+
+ @Override
+ public boolean reply(CloudEvent cloudEvent, SendCallback sendCallback) {
+ throw new StorageConnectorRuntimeException("Reply is not supported");
+ }
+
+ @Override
+ public void checkTopicExist(String topic) {
+ // Because redis has the feature of creating topics when used, there
is no need to check existence.
+ }
+
+ @Override
+ public void setExtFields() {
+
+ }
+}
diff --git
a/eventmesh-storage/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/storage/RedisStorageResourceService.java
b/eventmesh-storage/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/storage/RedisStorageResourceService.java
new file mode 100644
index 000000000..1846a194d
--- /dev/null
+++
b/eventmesh-storage/eventmesh-storage-redis/src/main/java/org/apache/eventmesh/storage/redis/storage/RedisStorageResourceService.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.eventmesh.storage.redis.storage;
+
+import org.apache.eventmesh.api.storage.StorageResourceService;
+
+public class RedisStorageResourceService implements StorageResourceService {
+
+ @Override
+ public void init() throws Exception {
+
+ }
+
+ @Override
+ public void release() throws Exception {
+
+ }
+}
diff --git
a/eventmesh-storage/eventmesh-storage-redis/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.consumer.Consumer
b/eventmesh-storage/eventmesh-storage-redis/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.consumer.Consumer
new file mode 100644
index 000000000..695ea9aba
--- /dev/null
+++
b/eventmesh-storage/eventmesh-storage-redis/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.consumer.Consumer
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+redis=org.apache.eventmesh.storage.redis.consumer.RedisConsumer
\ No newline at end of file
diff --git
a/eventmesh-storage/eventmesh-storage-redis/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.producer.Producer
b/eventmesh-storage/eventmesh-storage-redis/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.producer.Producer
new file mode 100644
index 000000000..553bf31ce
--- /dev/null
+++
b/eventmesh-storage/eventmesh-storage-redis/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.producer.Producer
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+redis=org.apache.eventmesh.storage.redis.producer.RedisProducer
\ No newline at end of file
diff --git
a/eventmesh-storage/eventmesh-storage-redis/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.storage.StorageResourceService
b/eventmesh-storage/eventmesh-storage-redis/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.storage.StorageResourceService
new file mode 100644
index 000000000..9dd64fbb7
--- /dev/null
+++
b/eventmesh-storage/eventmesh-storage-redis/src/main/resources/META-INF/eventmesh/org.apache.eventmesh.api.storage.StorageResourceService
@@ -0,0 +1,16 @@
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+
+redis=org.apache.eventmesh.storage.redis.storage.RedisStorageResourceService
\ No newline at end of file
diff --git
a/eventmesh-storage/eventmesh-storage-redis/src/main/resources/redis-client.properties
b/eventmesh-storage/eventmesh-storage-redis/src/main/resources/redis-client.properties
new file mode 100644
index 000000000..622297217
--- /dev/null
+++
b/eventmesh-storage/eventmesh-storage-redis/src/main/resources/redis-client.properties
@@ -0,0 +1,17 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+
diff --git
a/eventmesh-storage/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/AbstractRedisServer.java
b/eventmesh-storage/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/AbstractRedisServer.java
new file mode 100644
index 000000000..a71eeb6f9
--- /dev/null
+++
b/eventmesh-storage/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/AbstractRedisServer.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.eventmesh.storage.redis;
+
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+
+import ai.grakn.redismock.RedisServer;
+
+public abstract class AbstractRedisServer {
+
+ private static RedisServer redisServer;
+
+ @BeforeClass
+ public static void setupRedisServer() throws Exception {
+ redisServer = RedisServer.newRedisServer(6379);
+ redisServer.start();
+ }
+
+ @AfterClass
+ public static void shutdownRedisServer() {
+ if (redisServer != null) {
+ redisServer.stop();
+ }
+ }
+}
diff --git
a/eventmesh-storage/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/client/RedissonClientTest.java
b/eventmesh-storage/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/client/RedissonClientTest.java
new file mode 100644
index 000000000..fe18c76c8
--- /dev/null
+++
b/eventmesh-storage/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/client/RedissonClientTest.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.eventmesh.storage.redis.client;
+
+import org.apache.eventmesh.storage.redis.AbstractRedisServer;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class RedissonClientTest extends AbstractRedisServer {
+
+ @Test
+ public void testInstance() {
+ Assert.assertNotNull(RedissonClient.INSTANCE);
+ }
+}
\ No newline at end of file
diff --git
a/eventmesh-storage/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/config/RedisPropertiesTest.java
b/eventmesh-storage/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/config/RedisPropertiesTest.java
new file mode 100644
index 000000000..ad4e97785
--- /dev/null
+++
b/eventmesh-storage/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/config/RedisPropertiesTest.java
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.eventmesh.storage.redis.config;
+
+import org.apache.eventmesh.common.config.ConfigService;
+
+import java.util.Properties;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+public class RedisPropertiesTest {
+
+ @Test
+ public void getRedisProperties() {
+ ConfigService configService = ConfigService.getInstance();
+ RedisProperties config =
configService.buildConfigInstance(RedisProperties.class);
+ assertConfig(config);
+ }
+
+ private void assertConfig(RedisProperties config) {
+ Assert.assertEquals(config.getServerAddress(),
"redis://127.0.0.1:6379");
+ Assert.assertEquals(config.getServerType(),
RedisProperties.ServerType.SINGLE);
+ Assert.assertEquals(config.getServerMasterName(),
"serverMasterName-success!!!");
+
+ Properties properties = new Properties();
+ properties.put("threads", "2");
+ properties.put("nettyThreads", "2");
+ Properties redissonProperties = config.getRedissonProperties();
+ Assert.assertEquals(redissonProperties, properties);
+ }
+}
\ No newline at end of file
diff --git
a/eventmesh-storage/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/connector/UnitTest.java
b/eventmesh-storage/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/connector/UnitTest.java
new file mode 100644
index 000000000..d06990cd2
--- /dev/null
+++
b/eventmesh-storage/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/connector/UnitTest.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.eventmesh.storage.redis.connector;
+
+import org.apache.eventmesh.api.EventMeshAction;
+import org.apache.eventmesh.api.SendCallback;
+import org.apache.eventmesh.api.SendResult;
+import org.apache.eventmesh.api.exception.OnExceptionContext;
+import org.apache.eventmesh.storage.redis.AbstractRedisServer;
+import org.apache.eventmesh.storage.redis.consumer.RedisConsumer;
+import org.apache.eventmesh.storage.redis.consumer.RedisConsumerTest;
+import org.apache.eventmesh.storage.redis.producer.RedisProducer;
+
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.time.OffsetDateTime;
+import java.util.Properties;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import io.cloudevents.CloudEvent;
+import io.cloudevents.core.builder.CloudEventBuilder;
+
+public class UnitTest extends AbstractRedisServer {
+
+ private RedisProducer redisProducer;
+
+ private RedisConsumer redisConsumer;
+
+ @Before
+ public void setup() {
+ redisProducer = new RedisProducer();
+ redisProducer.init(new Properties());
+ redisProducer.start();
+
+ redisConsumer = new RedisConsumer();
+ redisConsumer.init(new Properties());
+ redisConsumer.start();
+ }
+
+ @After
+ public void shutdown() {
+ redisProducer.shutdown();
+ redisConsumer.shutdown();
+ }
+
+ @Test
+ public void testPubSub() throws Exception {
+
+ final int expectedCount = 3;
+ final CountDownLatch downLatch = new CountDownLatch(expectedCount);
+
+ redisConsumer.registerEventListener((cloudEvent, context) -> {
+ downLatch.countDown();
+ context.commit(EventMeshAction.CommitMessage);
+ }
+ );
+
+ final String topic = RedisConsumerTest.class.getSimpleName();
+
+ redisConsumer.subscribe(topic);
+
+ for (int i = 0; i < expectedCount; i++) {
+ CloudEvent cloudEvent = CloudEventBuilder.v1()
+ .withId(String.valueOf(i))
+ .withTime(OffsetDateTime.now())
+ .withSource(URI.create("testsource"))
+ .withSubject(topic)
+ .withType(String.class.getCanonicalName())
+ .withDataContentType("text/plain")
+ .withData("data".getBytes(StandardCharsets.UTF_8))
+ .build();
+
+ redisProducer.publish(cloudEvent, new SendCallback() {
+
+ @Override
+ public void onSuccess(SendResult sendResult) {
+
+ }
+
+ @Override
+ public void onException(OnExceptionContext context) {
+
+ }
+ });
+ }
+
+ Assert.assertTrue(downLatch.await(5, TimeUnit.MINUTES));
+ }
+}
diff --git
a/eventmesh-storage/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/consumer/RedisConsumerTest.java
b/eventmesh-storage/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/consumer/RedisConsumerTest.java
new file mode 100644
index 000000000..b29e034c0
--- /dev/null
+++
b/eventmesh-storage/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/consumer/RedisConsumerTest.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.eventmesh.storage.redis.consumer;
+
+import org.apache.eventmesh.api.EventMeshAction;
+import org.apache.eventmesh.storage.redis.AbstractRedisServer;
+import org.apache.eventmesh.storage.redis.client.RedissonClient;
+
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.time.OffsetDateTime;
+import java.util.Properties;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.redisson.api.RTopic;
+
+import io.cloudevents.CloudEvent;
+import io.cloudevents.core.builder.CloudEventBuilder;
+
+public class RedisConsumerTest extends AbstractRedisServer {
+
+ private RedisConsumer redisConsumer;
+
+ @Before
+ public void setup() {
+ redisConsumer = new RedisConsumer();
+ redisConsumer.init(new Properties());
+ redisConsumer.start();
+ }
+
+ @After
+ public void shutdown() {
+ redisConsumer.shutdown();
+ }
+
+ @Test
+ public void testSubscribe() throws Exception {
+
+ final int expectedCount = 3;
+ final CountDownLatch downLatch = new CountDownLatch(expectedCount);
+
+ redisConsumer.registerEventListener((cloudEvent, context) -> {
+ downLatch.countDown();
+ context.commit(EventMeshAction.CommitMessage);
+ }
+ );
+
+ final String topic = RedisConsumerTest.class.getSimpleName();
+
+ redisConsumer.subscribe(topic);
+
+ RTopic redissonTopic = RedissonClient.INSTANCE.getTopic(topic);
+ for (int i = 0; i < expectedCount; i++) {
+ CloudEvent cloudEvent = CloudEventBuilder.v1()
+ .withId(String.valueOf(i))
+ .withTime(OffsetDateTime.now())
+ .withSource(URI.create("testsource"))
+ .withSubject("topic")
+ .withType(String.class.getCanonicalName())
+ .withDataContentType("text/plain")
+ .withData("data".getBytes(StandardCharsets.UTF_8))
+ .build();
+
+ redissonTopic.publish(cloudEvent);
+ }
+
+ Assert.assertTrue(downLatch.await(5, TimeUnit.MINUTES));
+
+ redisConsumer.unsubscribe(topic);
+ }
+}
diff --git
a/eventmesh-storage/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/producer/RedisProducerTest.java
b/eventmesh-storage/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/producer/RedisProducerTest.java
new file mode 100644
index 000000000..946dcc830
--- /dev/null
+++
b/eventmesh-storage/eventmesh-storage-redis/src/test/java/org/apache/eventmesh/storage/redis/producer/RedisProducerTest.java
@@ -0,0 +1,110 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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 org.apache.eventmesh.storage.redis.producer;
+
+import org.apache.eventmesh.api.SendCallback;
+import org.apache.eventmesh.api.SendResult;
+import org.apache.eventmesh.api.exception.OnExceptionContext;
+import org.apache.eventmesh.storage.redis.AbstractRedisServer;
+
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.time.OffsetDateTime;
+import java.util.Properties;
+import java.util.UUID;
+import java.util.concurrent.CountDownLatch;
+
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+import io.cloudevents.CloudEvent;
+import io.cloudevents.core.builder.CloudEventBuilder;
+
+public class RedisProducerTest extends AbstractRedisServer {
+
+ private RedisProducer redisProducer;
+
+ @Before
+ public void setup() {
+ redisProducer = new RedisProducer();
+ redisProducer.init(new Properties());
+ redisProducer.start();
+ }
+
+ @After
+ public void shutdown() {
+ redisProducer.shutdown();
+ }
+
+ @Test
+ public void testPublish() throws Exception {
+ final int expectedCount = 3;
+ final CountDownLatch downLatch = new CountDownLatch(expectedCount);
+
+ for (int i = 0; i < expectedCount; i++) {
+ CloudEvent cloudEvent = CloudEventBuilder.v1()
+ .withId(String.valueOf(i))
+ .withTime(OffsetDateTime.now())
+ .withSource(URI.create("testsource"))
+ .withSubject(RedisProducerTest.class.getSimpleName())
+ .withType(String.class.getCanonicalName())
+ .withDataContentType("text/plain")
+ .withData("data".getBytes(StandardCharsets.UTF_8))
+ .build();
+
+ redisProducer.publish(cloudEvent, new SendCallback() {
+
+ @Override
+ public void onSuccess(SendResult sendResult) {
+ downLatch.countDown();
+ Assert.assertEquals(cloudEvent.getId(),
sendResult.getMessageId());
+ Assert.assertEquals(cloudEvent.getSubject(),
sendResult.getTopic());
+ }
+
+ @Override
+ public void onException(OnExceptionContext context) {
+ downLatch.countDown();
+ Assert.assertEquals(cloudEvent.getId(),
context.getMessageId());
+ Assert.assertEquals(cloudEvent.getSubject(),
context.getTopic());
+ }
+ });
+ }
+
+ downLatch.await();
+ }
+
+ @Test
+ public void testSendOneway() {
+
+ final String topic = RedisProducerTest.class.getSimpleName();
+
+ CloudEvent cloudEvent = CloudEventBuilder.v1()
+ .withId(UUID.randomUUID().toString())
+ .withTime(OffsetDateTime.now())
+ .withSource(URI.create("testsource"))
+ .withSubject(topic)
+ .withType(String.class.getCanonicalName())
+ .withDataContentType("text/plain")
+ .withData("data".getBytes())
+ .build();
+
+ redisProducer.sendOneway(cloudEvent);
+ }
+}
diff --git
a/eventmesh-storage/eventmesh-storage-redis/src/test/resources/redis-client.properties
b/eventmesh-storage/eventmesh-storage-redis/src/test/resources/redis-client.properties
new file mode 100644
index 000000000..7c89643f7
--- /dev/null
+++
b/eventmesh-storage/eventmesh-storage-redis/src/test/resources/redis-client.properties
@@ -0,0 +1,21 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one or more
+# contributor license agreements. See the NOTICE file distributed with
+# this work for additional information regarding copyright ownership.
+# The ASF licenses this file to You 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.
+#
+eventMesh.server.redis.serverAddress=redis://127.0.0.1:6379
+eventMesh.server.redis.serverType=SINGLE
+eventMesh.server.redis.serverMasterName=serverMasterName-success!!!
+eventMesh.server.redis.redisson.threads=2
+eventMesh.server.redis.redisson.nettyThreads=2
\ No newline at end of file
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]