Skip to content

Commit b71d7b3

Browse files
Aggressively Close Sockets
1 parent 30df9ac commit b71d7b3

File tree

1 file changed

+10
-6
lines changed

1 file changed

+10
-6
lines changed

core/shared/src/main/scala/io/chrisdavenport/rediculous/RedisConnection.scala

+10-6
Original file line numberDiff line numberDiff line change
@@ -47,9 +47,8 @@ object RedisConnection{
4747
) extends RedisConnection[F]{
4848
def runRequest(inputs: Chunk[NonEmptyList[ByteVector]], key: Option[ByteVector]): F[Chunk[Resp]] = {
4949
val chunk = Chunk.from(inputs.toList.map(Resp.renderRequest))
50-
def withSocket(socket: Socket[F]): F[Chunk[Resp]] = explicitPipelineRequest[F](socket, chunk, Defaults.maxBytes, redisRequestTimeout)
5150
pool.take(()).use{
52-
m => withSocket(m.value).timeout(redisRequestTimeout).attempt.flatTap{
51+
m => explicitPipelineRequest[F](m.value, chunk, Defaults.maxBytes, redisRequestTimeout, m.canBeReused.set(Reusable.DontReuse)).timeout(redisRequestTimeout).attempt.flatTap{
5352
case Left(_) => m.canBeReused.set(Reusable.DontReuse)
5453
case _ => Applicative[F].unit
5554
}
@@ -60,7 +59,7 @@ object RedisConnection{
6059
private[rediculous] case class DirectConnection[F[_]: Temporal](socket: Socket[F], commandTimeout: Duration, redisRequestTimeout: Duration) extends RedisConnection[F]{
6160
def runRequest(inputs: Chunk[NonEmptyList[ByteVector]], key: Option[ByteVector]): F[Chunk[Resp]] = {
6261
val chunk = Chunk.from(inputs.toList.map(Resp.renderRequest))
63-
def withSocket(socket: Socket[F]): F[Chunk[Resp]] = explicitPipelineRequest[F](socket, chunk, Defaults.maxBytes, redisRequestTimeout)
62+
def withSocket(socket: Socket[F]): F[Chunk[Resp]] = explicitPipelineRequest[F](socket, chunk, Defaults.maxBytes, redisRequestTimeout, socket.endOfOutput)
6463
withSocket(socket)
6564
}.timeoutTo(commandTimeout, Defer[F].defer(Temporal[F].raiseError[Chunk[Resp]](RedisError.CommandTimeoutException(commandTimeout))))
6665
}
@@ -78,14 +77,18 @@ object RedisConnection{
7877

7978
// Guarantees With Socket That Each Call Receives a Response
8079
// Chunk must be non-empty but to do so incurs a penalty
81-
private[rediculous] def explicitPipelineRequest[F[_]: Temporal](socket: Socket[F], calls: Chunk[Resp], maxBytes: Int, redisRequestTimeout: Duration): F[Chunk[Resp]] = {
80+
private[rediculous] def explicitPipelineRequest[F[_]: Temporal](socket: Socket[F], calls: Chunk[Resp], maxBytes: Int, redisRequestTimeout: Duration, removeConnection: F[Unit]): F[Chunk[Resp]] = {
8281
val out = calls.flatMap(resp =>
8382
Resp.CodecUtils.codec.encode(resp).toEither.traverse(bits => Chunk.byteVector(bits.bytes))
8483
).sequence.leftMap(err => new Throwable(s"Failed To Encode Response $err")).liftTo[F]
8584
out.flatMap{bytes =>
8685

8786
val request = socket.write(bytes) >>
8887
Stream.eval(socket.read(maxBytes))
88+
.evalTap{
89+
case None => removeConnection
90+
case _ => Applicative[F].unit
91+
}
8992
.repeat
9093
.unNoneTerminate
9194
.unchunks
@@ -95,6 +98,7 @@ object RedisConnection{
9598
.to(Chunk)
9699

97100
request.timeoutTo(redisRequestTimeout, Defer[F].defer(Temporal[F].raiseError[Chunk[Resp]](RedisError.RedisRequestTimeoutException(redisRequestTimeout))))
101+
.onError{ case _ => removeConnection }
98102
}
99103
}
100104

@@ -497,7 +501,7 @@ object RedisConnection{
497501
keypool.take(()).attempt.use{
498502
case Right(m) =>
499503
val out = chunk.map(_._2)
500-
explicitPipelineRequest(m.value, out, Defaults.maxBytes, redisRequestTimeout)
504+
explicitPipelineRequest(m.value, out, Defaults.maxBytes, redisRequestTimeout, m.canBeReused.set(Reusable.DontReuse))
501505
.attempt
502506
.timeout(redisRequestTimeout) // Apply Timeout To Call to Redis, this is independent of the timeout on individual calls
503507
.flatTap{// Currently Guarantee Chunk.size === returnSize
@@ -718,7 +722,7 @@ object RedisConnection{
718722
keypool.take(server).attempt.use{
719723
case Right(m) =>
720724
val out = Chunk.from(rest.map(_._5))
721-
explicitPipelineRequest(m.value, out, Defaults.maxBytes, redisRequestTimeout).attempt.flatTap{// Currently Guarantee Chunk.size === returnSize
725+
explicitPipelineRequest(m.value, out, Defaults.maxBytes, redisRequestTimeout, m.canBeReused.set(Reusable.DontReuse)).attempt.flatTap{// Currently Guarantee Chunk.size === returnSize
722726
case Left(_) => m.canBeReused.set(Reusable.DontReuse)
723727
case _ => Applicative[F].unit
724728
}

0 commit comments

Comments
 (0)