diff --git a/pom.xml b/pom.xml
index be8ee579e..193132c66 100644
--- a/pom.xml
+++ b/pom.xml
@@ -178,6 +178,40 @@
test
+
+
+ org.jetbrains.kotlin
+ kotlin-stdlib
+ true
+
+
+
+ org.jetbrains.kotlin
+ kotlin-reflect
+ true
+
+
+
+ org.jetbrains.kotlinx
+ kotlinx-coroutines-core
+ ${kotlin-coroutines}
+ true
+
+
+
+ org.jetbrains.kotlinx
+ kotlinx-coroutines-reactor
+ ${kotlin-coroutines}
+ true
+
+
+
+ io.mockk
+ mockk
+ ${mockk}
+ test
+
+
diff --git a/src/main/kotlin/org/springframework/data/redis/core/ReactiveGeoOperationsExtensions.kt b/src/main/kotlin/org/springframework/data/redis/core/ReactiveGeoOperationsExtensions.kt
new file mode 100644
index 000000000..f028ab8cc
--- /dev/null
+++ b/src/main/kotlin/org/springframework/data/redis/core/ReactiveGeoOperationsExtensions.kt
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2019 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
+ *
+ * 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.springframework.data.redis.core
+
+import kotlinx.coroutines.reactive.awaitFirstOrNull
+import kotlinx.coroutines.reactive.awaitSingle
+import org.springframework.data.geo.Distance
+import org.springframework.data.geo.Metric
+import org.springframework.data.geo.Point
+import org.springframework.data.redis.connection.RedisGeoCommands
+
+/**
+ * Coroutines variant of [ReactiveGeoOperations.add].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveGeoOperations.addAndAwait(key: K, point: Point, member: M): Long =
+ add(key, point, member).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveGeoOperations.add].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveGeoOperations.addAndAwait(key: K, location: RedisGeoCommands.GeoLocation): Long =
+ add(key, location).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveGeoOperations.add].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveGeoOperations.addAndAwait(key: K, memberCoordinateMap: Map): Long =
+ add(key, memberCoordinateMap).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveGeoOperations.add].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveGeoOperations.addAndAwait(key: K, locations: Iterable>): Long =
+ add(key, locations).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveGeoOperations.distance].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveGeoOperations.distanceAndAwait(key: K, member1: M, member2: M): Distance =
+ distance(key, member1, member2).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveGeoOperations.distance].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveGeoOperations.distanceAndAwait(key: K, member1: M, member2: M, metric: Metric): Distance =
+ distance(key, member1, member2, metric).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveGeoOperations.hash].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveGeoOperations.hashAndAwait(key: K, member: M): String =
+ hash(key, member).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveGeoOperations.hash].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveGeoOperations.hashAndAwait(key: K, vararg member: M): List =
+ hash(key, *member).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveGeoOperations.position].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveGeoOperations.positionAndAwait(key: K, member: M): Point? =
+ position(key, member).awaitFirstOrNull()
+
+/**
+ * Coroutines variant of [ReactiveGeoOperations.position].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveGeoOperations.positionAndAwait(key: K, vararg members: M): List =
+ position(key, *members).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveGeoOperations.remove].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveGeoOperations.removeAndAwait(key: K, vararg member: M): Long =
+ remove(key, *member).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveGeoOperations.delete].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveGeoOperations.deleteAndAwait(key: K): Boolean =
+ delete(key).awaitSingle()
diff --git a/src/main/kotlin/org/springframework/data/redis/core/ReactiveHashOperationsExtensions.kt b/src/main/kotlin/org/springframework/data/redis/core/ReactiveHashOperationsExtensions.kt
new file mode 100644
index 000000000..934982d81
--- /dev/null
+++ b/src/main/kotlin/org/springframework/data/redis/core/ReactiveHashOperationsExtensions.kt
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2019 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
+ *
+ * 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.springframework.data.redis.core
+
+import kotlinx.coroutines.reactive.awaitSingle
+
+/**
+ * Coroutines variant of [ReactiveHashOperations.hasKey].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveHashOperations.hasKeyAndAwait(key: H, hashKey: HK): Boolean =
+ hasKey(key, hashKey).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveHashOperations.get].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveHashOperations.getAndAwait(key: H, hashKey: HK): HV =
+ get(key, hashKey).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveHashOperations.multiGet].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveHashOperations.multiGetAndAwait(key: H, vararg hashKeys: HK): List =
+ multiGet(key, hashKeys.toCollection(ArrayList())).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveHashOperations.increment].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveHashOperations.incrementAndAwait(key: H, hashKey: HK, delta: Long): Long =
+ increment(key, hashKey, delta).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveHashOperations.increment].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveHashOperations.incrementAndAwait(key: H, hashKey: HK, delta: Double): Double =
+ increment(key, hashKey, delta).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveHashOperations.size].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveHashOperations.sizeAndAwait(key: H): Long =
+ size(key).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveHashOperations.putAll].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveHashOperations.putAllAndAwait(key: H, map: Map): Boolean =
+ putAll(key, map).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveHashOperations.put].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveHashOperations.putAndAwait(key: H, hashKey: HK, hashValue: HV): Boolean =
+ put(key, hashKey, hashValue).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveHashOperations.putIfAbsent].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveHashOperations.putIfAbsentAndAwait(key: H, hashKey: HK, hashValue: HV): Boolean =
+ putIfAbsent(key, hashKey, hashValue).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveHashOperations.remove].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveHashOperations.removeAndAwait(key: H, vararg hashKeys: Any): Long =
+ remove(key, *hashKeys).awaitSingle()
diff --git a/src/main/kotlin/org/springframework/data/redis/core/ReactiveHyperLogLogOperationsExtensions.kt b/src/main/kotlin/org/springframework/data/redis/core/ReactiveHyperLogLogOperationsExtensions.kt
new file mode 100644
index 000000000..ad794ed06
--- /dev/null
+++ b/src/main/kotlin/org/springframework/data/redis/core/ReactiveHyperLogLogOperationsExtensions.kt
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2019 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
+ *
+ * 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.springframework.data.redis.core
+
+import kotlinx.coroutines.reactive.awaitSingle
+
+/**
+ * Coroutines variant of [ReactiveHyperLogLogOperations.add].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveHyperLogLogOperations.addAndAwait(key: K, vararg values: V): Long =
+ add(key, *values).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveHyperLogLogOperations.size].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveHyperLogLogOperations.sizeAndAwait(vararg keys: K): Long =
+ size(*keys).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveHyperLogLogOperations.union].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveHyperLogLogOperations.unionAndAwait(destination: K, vararg sourceKeys: K): Boolean =
+ union(destination, *sourceKeys).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveHyperLogLogOperations.delete].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveHyperLogLogOperations.deleteAndAwait(key: K): Boolean =
+ delete(key).awaitSingle()
diff --git a/src/main/kotlin/org/springframework/data/redis/core/ReactiveListOperationsExtensions.kt b/src/main/kotlin/org/springframework/data/redis/core/ReactiveListOperationsExtensions.kt
new file mode 100644
index 000000000..2282735e9
--- /dev/null
+++ b/src/main/kotlin/org/springframework/data/redis/core/ReactiveListOperationsExtensions.kt
@@ -0,0 +1,200 @@
+/*
+ * Copyright 2019 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
+ *
+ * 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.springframework.data.redis.core
+
+import kotlinx.coroutines.reactive.awaitFirstOrNull
+import kotlinx.coroutines.reactive.awaitSingle
+import java.time.Duration
+
+/**
+ * Coroutines variant of [ReactiveListOperations.trim].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveListOperations.trimAndAwait(key: K, start: Long, end: Long): Boolean =
+ trim(key, start, end).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveListOperations.size].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveListOperations.sizeAndAwait(key: K): Long =
+ size(key).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveListOperations.leftPush].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveListOperations.leftPushAndAwait(key: K, value: V): Long =
+ leftPush(key, value).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveListOperations.leftPushAll].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveListOperations.leftPushAllAndAwait(key: K, vararg values: V): Long =
+ leftPushAll(key, *values).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveListOperations.leftPushAll].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveListOperations.leftPushAllAndAwait(key: K, values: Collection): Long =
+ leftPushAll(key, values).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveListOperations.leftPushIfPresent].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveListOperations.leftPushIfPresentAndAwait(key: K, value: V): Long =
+ leftPushIfPresent(key, value).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveListOperations.leftPushIfPresent].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveListOperations.leftPushAndAwait(key: K, pivot: V, value: V): Long =
+ leftPush(key, pivot, value).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveListOperations.rightPush].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveListOperations.rightPushAndAwait(key: K, value: V): Long =
+ rightPush(key, value).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveListOperations.rightPushAll].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveListOperations.rightPushAllAndAwait(key: K, vararg values: V): Long =
+ rightPushAll(key, *values).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveListOperations.rightPushAll].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveListOperations.rightPushAllAndAwait(key: K, values: Collection): Long =
+ rightPushAll(key, values).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveListOperations.rightPushIfPresent].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveListOperations.rightPushIfPresentAndAwait(key: K, value: V): Long =
+ rightPushIfPresent(key, value).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveListOperations.rightPushIfPresent].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveListOperations.rightPushAndAwait(key: K, pivot: V, value: V): Long =
+ rightPush(key, pivot, value).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveListOperations.set].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveListOperations.setAndAwait(key: K, index: Long, value: V): Boolean =
+ set(key, index, value).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveListOperations.remove].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveListOperations.removeAndAwait(key: K, count: Long, value: V): Long =
+ remove(key, count, value).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveListOperations.index].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveListOperations.indexAndAwait(key: K, index: Long): V? =
+ index(key, index).awaitFirstOrNull()
+
+/**
+ * Coroutines variant of [ReactiveListOperations.leftPop].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveListOperations.leftPopAndAwait(key: K): V? =
+ leftPop(key).awaitFirstOrNull()
+
+/**
+ * Coroutines variant of [ReactiveListOperations.leftPop].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveListOperations.leftPopAndAwait(key: K, timeout: Duration): V? =
+ leftPop(key, timeout).awaitFirstOrNull()
+
+/**
+ * Coroutines variant of [ReactiveListOperations.rightPop].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveListOperations.rightPopAndAwait(key: K): V? =
+ rightPop(key).awaitFirstOrNull()
+
+/**
+ * Coroutines variant of [ReactiveListOperations.rightPop].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveListOperations.rightPopAndAwait(key: K, timeout: Duration): V? =
+ rightPop(key, timeout).awaitFirstOrNull()
+
+/**
+ * Coroutines variant of [ReactiveListOperations.delete].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveListOperations.deleteAndAwait(key: K): Boolean =
+ delete(key).awaitSingle()
diff --git a/src/main/kotlin/org/springframework/data/redis/core/ReactiveRedisOperationsExtensions.kt b/src/main/kotlin/org/springframework/data/redis/core/ReactiveRedisOperationsExtensions.kt
new file mode 100644
index 000000000..ac7620d61
--- /dev/null
+++ b/src/main/kotlin/org/springframework/data/redis/core/ReactiveRedisOperationsExtensions.kt
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2019 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
+ *
+ * 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.springframework.data.redis.core
+
+import kotlinx.coroutines.reactive.awaitFirstOrNull
+import kotlinx.coroutines.reactive.awaitSingle
+import org.springframework.data.redis.connection.DataType
+import java.time.Duration
+import java.time.Instant
+
+/**
+ * Coroutines variant of [ReactiveRedisOperations.convertAndSend].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveRedisOperations.sendAndAwait(destination: String, message: V): Long =
+ convertAndSend(destination, message).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveRedisOperations.hasKey].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveRedisOperations.hasKeyAndAwait(key: K): Boolean =
+ hasKey(key).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveRedisOperations.type].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveRedisOperations.typeAndAwait(key: K): DataType =
+ type(key).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveRedisOperations.randomKey].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveRedisOperations.randomKeyAndAwait(): K? =
+ randomKey().awaitFirstOrNull()
+
+/**
+ * Coroutines variant of [ReactiveRedisOperations.rename].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveRedisOperations.renameAndAwait(oldKey: K, newKey: K): Boolean =
+ rename(oldKey, newKey).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveRedisOperations.renameIfAbsent].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveRedisOperations.renameIfAbsentAndAwait(oldKey: K, newKey: K): Boolean =
+ renameIfAbsent(oldKey, newKey).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveRedisOperations.delete].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveRedisOperations.deleteAndAwait(vararg key: K): Long =
+ delete(*key).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveRedisOperations.unlink].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveRedisOperations.unlinkAndAwait(vararg key: K): Long =
+ unlink(*key).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveRedisOperations.expire].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveRedisOperations.expireAndAwait(key: K, timeout: Duration): Boolean =
+ expire(key, timeout).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveRedisOperations.expireAt].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveRedisOperations.expireAtAndAwait(key: K, expireAt: Instant): Boolean = expireAt(key, expireAt).awaitSingle()
+
+
+/**
+ * Coroutines variant of [ReactiveRedisOperations.persist].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveRedisOperations.persistAndAwait(key: K): Boolean =
+ persist(key).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveRedisOperations.move].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveRedisOperations.moveAndAwait(key: K, dbIndex: Int): Boolean = move(key, dbIndex).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveRedisOperations.getExpire].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveRedisOperations.getExpireAndAwait(key: K): Duration? = getExpire(key).awaitFirstOrNull()
diff --git a/src/main/kotlin/org/springframework/data/redis/core/ReactiveSetOperationsExtensions.kt b/src/main/kotlin/org/springframework/data/redis/core/ReactiveSetOperationsExtensions.kt
new file mode 100644
index 000000000..24a97fe99
--- /dev/null
+++ b/src/main/kotlin/org/springframework/data/redis/core/ReactiveSetOperationsExtensions.kt
@@ -0,0 +1,147 @@
+/*
+ * Copyright 2019 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
+ *
+ * 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.springframework.data.redis.core
+
+import kotlinx.coroutines.reactive.awaitFirstOrNull
+import kotlinx.coroutines.reactive.awaitSingle
+
+/**
+ * Coroutines variant of [ReactiveSetOperations.add].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveSetOperations.addAndAwait(key: K, vararg values: V): Long =
+ add(key, *values).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveSetOperations.remove].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveSetOperations.removeAndAwait(key: K, vararg values: V): Long =
+ remove(key, *values).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveSetOperations.pop].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveSetOperations.popAndAwait(key: K): V? =
+ pop(key).awaitFirstOrNull()
+
+/**
+ * Coroutines variant of [ReactiveSetOperations.move].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveSetOperations.moveAndAwait(sourceKey: K, value: V, destKey: K): Boolean =
+ move(sourceKey, value, destKey).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveSetOperations.size].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveSetOperations.sizeAndAwait(key: K): Long =
+ size(key).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveSetOperations.isMember].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveSetOperations.isMemberAndAwait(key: K, value: V): Boolean =
+ isMember(key, value).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveSetOperations.intersectAndStore].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveSetOperations.intersectAndStoreAndAwait(key: K, otherKey: K, destKey: K): Long =
+ intersectAndStore(key, otherKey, destKey).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveSetOperations.intersectAndStore].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveSetOperations.intersectAndStoreAndAwait(keys: Collection, destKey: K): Long =
+ intersectAndStore(keys, destKey).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveSetOperations.unionAndStore].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveSetOperations.unionAndStoreAndAwait(key: K, otherKey: K, destKey: K): Long =
+ unionAndStore(key, otherKey, destKey).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveSetOperations.unionAndStore].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveSetOperations.unionAndStoreAndAwait(keys: Collection, destKey: K): Long =
+ unionAndStore(keys, destKey).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveSetOperations.differenceAndStore].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveSetOperations.differenceAndStoreAndAwait(key: K, otherKey: K, destKey: K): Long =
+ differenceAndStore(key, otherKey, destKey).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveSetOperations.differenceAndStore].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveSetOperations.differenceAndStoreAndAwait(keys: Collection, destKey: K): Long =
+ differenceAndStore(keys, destKey).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveSetOperations.randomMember].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveSetOperations.randomMemberAndAwait(key: K): V? =
+ randomMember(key).awaitFirstOrNull()
+
+/**
+ * Coroutines variant of [ReactiveSetOperations.delete].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveSetOperations.deleteAndAwait(key: K): Boolean =
+ delete(key).awaitSingle()
+
+
diff --git a/src/main/kotlin/org/springframework/data/redis/core/ReactiveStreamOperationsExtensions.kt b/src/main/kotlin/org/springframework/data/redis/core/ReactiveStreamOperationsExtensions.kt
new file mode 100644
index 000000000..5feafa497
--- /dev/null
+++ b/src/main/kotlin/org/springframework/data/redis/core/ReactiveStreamOperationsExtensions.kt
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2019 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
+ *
+ * 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.springframework.data.redis.core
+
+import kotlinx.coroutines.reactive.awaitSingle
+import org.springframework.data.redis.connection.stream.*
+
+/**
+ * Coroutines variant of [ReactiveStreamOperations.acknowledge].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveStreamOperations.acknowledgeAndAwait(key: K, group: String, vararg recordIds: String): Long =
+ acknowledge(key, group, *recordIds).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveStreamOperations.acknowledge].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveStreamOperations.acknowledgeAndAwait(key: K, group: String, vararg recordIds: RecordId): Long =
+ acknowledge(key, group, *recordIds).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveStreamOperations.acknowledge].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveStreamOperations.acknowledgeAndAwait(group: String, record: Record): Long =
+ acknowledge(group, record).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveStreamOperations.add].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveStreamOperations.addAndAwait(record: MapRecord): RecordId =
+ add(record).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveStreamOperations.add].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveStreamOperations.addAndAwait(record: Record): RecordId =
+ add(record).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveStreamOperations.delete].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveStreamOperations.deleteAndAwait(key: K, vararg recordIds: String): Long =
+ delete(key, *recordIds).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveStreamOperations.delete].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveStreamOperations.deleteAndAwait(record: Record): Long =
+ delete(record).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveStreamOperations.delete].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveStreamOperations.deleteAndAwait(key: K, vararg recordIds: RecordId): Long =
+ delete(key, *recordIds).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveStreamOperations.createGroup].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveStreamOperations.createGroupAndAwait(key: K, group: String): String =
+ createGroup(key, group).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveStreamOperations.createGroup].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveStreamOperations.createGroupAndAwait(key: K, readOffset: ReadOffset, group: String): String =
+ createGroup(key, readOffset, group).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveStreamOperations.deleteConsumer].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveStreamOperations.deleteConsumerAndAwait(key: K, consumer: Consumer): String =
+ deleteConsumer(key, consumer).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveStreamOperations.destroyGroup].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveStreamOperations.destroyGroupAndAwait(key: K, group: String): String =
+ destroyGroup(key, group).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveStreamOperations.size].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveStreamOperations.sizeAndAwait(key: K): Long =
+ size(key).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveStreamOperations.trim].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveStreamOperations.trimAndAwait(key: K, count: Long): Long =
+ trim(key, count).awaitSingle()
diff --git a/src/main/kotlin/org/springframework/data/redis/core/ReactiveValueOperationsExtensions.kt b/src/main/kotlin/org/springframework/data/redis/core/ReactiveValueOperationsExtensions.kt
new file mode 100644
index 000000000..db88967ba
--- /dev/null
+++ b/src/main/kotlin/org/springframework/data/redis/core/ReactiveValueOperationsExtensions.kt
@@ -0,0 +1,246 @@
+/*
+ * Copyright 2019 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
+ *
+ * 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.springframework.data.redis.core
+
+import kotlinx.coroutines.reactive.awaitFirstOrNull
+import kotlinx.coroutines.reactive.awaitSingle
+import org.springframework.data.redis.connection.BitFieldSubCommands
+import java.time.Duration
+
+/**
+ * Coroutines variant of [ReactiveValueOperations.set].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveValueOperations.setAndAwait(key: K, value: V): Boolean =
+ set(key, value).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveValueOperations.set].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveValueOperations.setAndAwait(key: K, value: V, timeout: Duration): Boolean =
+ set(key, value, timeout).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveValueOperations.setIfAbsent].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveValueOperations.setIfAbsentAndAwait(key: K, value: V): Boolean =
+ setIfAbsent(key, value).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveValueOperations.setIfAbsent].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveValueOperations.setIfAbsentAndAwait(key: K, value: V, timeout: Duration): Boolean =
+ setIfAbsent(key, value, timeout).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveValueOperations.setIfPresent].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveValueOperations.setIfPresentAndAwait(key: K, value: V): Boolean =
+ setIfPresent(key, value).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveValueOperations.setIfPresent].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveValueOperations.setIfPresentAndAwait(key: K, value: V, timeout: Duration): Boolean =
+ setIfPresent(key, value, timeout).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveValueOperations.multiSet].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveValueOperations.multiSetAndAwait(map: Map): Boolean =
+ multiSet(map).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveValueOperations.multiSetIfAbsent].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveValueOperations.multiSetIfAbsentAndAwait(map: Map): Boolean =
+ multiSetIfAbsent(map).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveValueOperations.get].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveValueOperations.getAndAwait(key: K): V? =
+ get(key).awaitFirstOrNull()
+
+/**
+ * Coroutines variant of [ReactiveValueOperations.getAndSet].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveValueOperations.getAndSetAndAwait(key: K, value: V): V? =
+ getAndSet(key, value).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveValueOperations.multiGet].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveValueOperations.multiGetAndAwait(vararg keys: K): List =
+ multiGet(keys.toCollection(ArrayList())).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveValueOperations.multiGet].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveValueOperations.multiGetAndAwait(keys: Collection): List =
+ multiGet(keys).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveValueOperations.increment].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveValueOperations.incrementAndAwait(key: K): Long =
+ increment(key).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveValueOperations.increment].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveValueOperations.incrementAndAwait(key: K, delta: Long): Long =
+ increment(key, delta).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveValueOperations.increment].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveValueOperations.incrementAndAwait(key: K, delta: Double): Double =
+ increment(key, delta).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveValueOperations.decrement].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveValueOperations.decrementAndAwait(key: K): Long =
+ decrement(key).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveValueOperations.decrement].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveValueOperations.decrementAndAwait(key: K, delta: Long): Long =
+ decrement(key, delta).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveValueOperations.append].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveValueOperations.appendAndAwait(key: K, value: String): Long =
+ append(key, value).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveValueOperations.get].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveValueOperations.getAndAwait(key: K, start: Long, end: Long): String? =
+ get(key, start, end).awaitFirstOrNull()
+
+/**
+ * Coroutines variant of [ReactiveValueOperations.set].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveValueOperations.setAndAwait(key: K, value: V, offset: Long): Long =
+ set(key, value, offset).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveValueOperations.size].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveValueOperations.sizeAndAwait(key: K): Long? =
+ size(key).awaitFirstOrNull()
+
+/**
+ * Coroutines variant of [ReactiveValueOperations.setBit].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveValueOperations.setBitAndAwait(key: K, offset: Long, value: Boolean): Boolean =
+ setBit(key, offset, value).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveValueOperations.getBit].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveValueOperations.getBitAndAwait(key: K, offset: Long): Boolean =
+ getBit(key, offset).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveValueOperations.bitField].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveValueOperations.bitFieldAndAwait(key: K, commands: BitFieldSubCommands): List =
+ bitField(key, commands).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveValueOperations.delete].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveValueOperations.deleteAndAwait(key: K): Boolean =
+ delete(key).awaitSingle()
diff --git a/src/main/kotlin/org/springframework/data/redis/core/ReactiveZSetOperationsExtensions.kt b/src/main/kotlin/org/springframework/data/redis/core/ReactiveZSetOperationsExtensions.kt
new file mode 100644
index 000000000..16ad572c1
--- /dev/null
+++ b/src/main/kotlin/org/springframework/data/redis/core/ReactiveZSetOperationsExtensions.kt
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2019 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
+ *
+ * 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.springframework.data.redis.core
+
+import kotlinx.coroutines.reactive.awaitFirstOrNull
+import kotlinx.coroutines.reactive.awaitSingle
+import org.springframework.data.domain.Range
+import org.springframework.data.redis.connection.RedisZSetCommands
+
+/**
+ * Coroutines variant of [ReactiveZSetOperations.add].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveZSetOperations.addAndAwait(key: K, value: V, score: Double): Boolean =
+ add(key, value, score).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveZSetOperations.addAll].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveZSetOperations.addAllAndAwait(key: K, values: Collection>): Long =
+ addAll(key, values).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveZSetOperations.remove].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun ReactiveZSetOperations.removeAndAwait(key: K, vararg values: Any): Long =
+ remove(key, *values).awaitSingle()
+
+/**
+ * Coroutines variant of [ReactiveZSetOperations.incrementScore].
+ *
+ * @author Mark Paluch
+ * @since 2.2
+ */
+suspend inline fun