-
Notifications
You must be signed in to change notification settings - Fork 38
Improve reconnection settings #74
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 5 commits
e4eb99c
9782806
dffac61
d9223e4
f9015d9
e6eaaf6
deefa68
2522043
039b040
d752e92
76a7102
e9aab41
d1f8f58
5db9a52
963c025
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -46,17 +46,17 @@ private [redis] class RedisConnection(remote: InetSocketAddress, settings: Redis | |
| context watch pipe | ||
|
|
||
| case CommandFailed(c: Connect) => | ||
| settings.reconnectionSettings match { | ||
| case Some(r) => | ||
| if (reconnectionSchedule.isEmpty) { | ||
| reconnectionSchedule = Some(settings.reconnectionSettings.get.newSchedule) | ||
| } | ||
| val delayMs = reconnectionSchedule.get.nextDelayMs | ||
| log.error("Connect failed for {} with {}. Reconnecting in {} ms... ", c.remoteAddress, c.failureMessage, delayMs) | ||
| context.system.scheduler.scheduleOnce(Duration(delayMs, TimeUnit.MILLISECONDS), IO(Tcp), Connect(remote))(context.dispatcher, self) | ||
| case None => | ||
| log.error("Connect failed for {} with {}. Stopping... ", c.remoteAddress, c.failureMessage) | ||
| context stop self | ||
| if (reconnectionSchedule.isEmpty) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should we keep it as an
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good call. I'll make those changes. |
||
| reconnectionSchedule = Some(settings.reconnectionSettings.newSchedule) | ||
| } | ||
| if (reconnectionSchedule.get.attempts < reconnectionSchedule.get.maxAttempts) { | ||
| val delayMs = reconnectionSchedule.get.nextDelayMs | ||
| log.error("Connect failed for {} with {}. Reconnecting in {} ms... ", c.remoteAddress, c.failureMessage, delayMs) | ||
| context become unconnected | ||
| context.system.scheduler.scheduleOnce(Duration(delayMs, TimeUnit.MILLISECONDS), IO(Tcp), Connect(remote))(context.dispatcher, self) | ||
| } else { | ||
| log.error("Connect failed for {} with {}. Stopping... ", c.remoteAddress, c.failureMessage) | ||
| context stop self | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -123,18 +123,17 @@ private [redis] class RedisConnection(remote: InetSocketAddress, settings: Redis | |
|
|
||
| def withTerminationManagement(handler: Receive): Receive = handler orElse { | ||
| case Terminated(x) => { | ||
| settings.reconnectionSettings match { | ||
| case Some(r) => | ||
| if (reconnectionSchedule.isEmpty) { | ||
| reconnectionSchedule = Some(settings.reconnectionSettings.get.newSchedule) | ||
| } | ||
| val delayMs = reconnectionSchedule.get.nextDelayMs | ||
| log.error("Child termination detected: {}. Reconnecting in {} ms... ", x, delayMs) | ||
| context become unconnected | ||
| context.system.scheduler.scheduleOnce(Duration(delayMs, TimeUnit.MILLISECONDS), IO(Tcp), Connect(remote))(context.dispatcher, self) | ||
| case None => | ||
| log.error("Child termination detected: {}", x) | ||
| context stop self | ||
| if (reconnectionSchedule.isEmpty) { | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Same here. |
||
| reconnectionSchedule = Some(settings.reconnectionSettings.newSchedule) | ||
| } | ||
| if (reconnectionSchedule.get.attempts < reconnectionSchedule.get.maxAttempts) { | ||
| val delayMs = reconnectionSchedule.get.nextDelayMs | ||
| log.error("Child termination detected: {}. Reconnecting in {} ms... ", x, delayMs) | ||
| context become unconnected | ||
| context.system.scheduler.scheduleOnce(Duration(delayMs, TimeUnit.MILLISECONDS), IO(Tcp), Connect(remote))(context.dispatcher, self) | ||
| } else { | ||
| log.error("Child termination detected: {}", x) | ||
| context stop self | ||
| } | ||
| } | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -2,31 +2,36 @@ package com.redis | |
|
|
||
| import scala.concurrent.duration._ | ||
|
|
||
| import akka.util.Timeout | ||
| import akka.actor._ | ||
| import akka.testkit.TestKit | ||
| import akka.util.Timeout | ||
| import com.redis.RedisClientSettings.ConstantReconnectionSettings | ||
| import org.scalatest._ | ||
| import org.scalatest.concurrent.{Futures, ScalaFutures} | ||
| import org.scalatest.time._ | ||
|
|
||
| trait RedisSpecBase extends FunSpec | ||
| class RedisSpecBase(_system: ActorSystem) extends TestKit(_system) | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Nice :) |
||
| with FunSpecLike | ||
| with Matchers | ||
| with Futures | ||
| with ScalaFutures | ||
| with BeforeAndAfterEach | ||
| with BeforeAndAfterAll { | ||
| import RedisSpecBase._ | ||
|
|
||
| // Akka setup | ||
| implicit val system = ActorSystem("redis-test-"+ iter.next) | ||
| def this() = this(ActorSystem("redis-test-"+ RedisSpecBase.iter.next)) | ||
| implicit val executionContext = system.dispatcher | ||
| implicit val timeout = Timeout(2 seconds) | ||
|
|
||
| // Scalatest setup | ||
| implicit val defaultPatience = PatienceConfig(timeout = Span(5, Seconds), interval = Span(5, Millis)) | ||
|
|
||
| // Redis client setup | ||
| val client = RedisClient("localhost", 6379, settings = RedisClientSettings(reconnectionSettings = Some(ConstantReconnectionSettings(1000)))) | ||
| val client = RedisClient("localhost", 6379) | ||
|
|
||
| def withReconnectingClient(testCode: RedisClient => Any) = { | ||
| val client = RedisClient("localhost", 6379, settings = RedisClientSettings(reconnectionSettings = ConstantReconnectionSettings(1000))) | ||
| testCode(client) | ||
| } | ||
|
|
||
| override def beforeEach = { | ||
| client.flushdb() | ||
|
|
@@ -50,6 +55,6 @@ trait RedisSpecBase extends FunSpec | |
|
|
||
| object RedisSpecBase { | ||
|
|
||
| private val iter = Iterator from 0 | ||
| val iter = Iterator from 0 | ||
|
|
||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure if a command failure always means disconnection. As we already have termination management, another failure handling strategy might be needed IMHO.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So I think that means in this block the
IO(Tcp) ! Connectfailed. Wouldn't the same reconnection strategy apply to failed connections?I did remove the
context become unconnectedsince we are already in that state.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually
CommandFailedresults fromConnectmessage to the TCP manager. I think specifying an incorrectInetSocketAddresswill also result in aCommandFailedmessage.CommandFailedcan come also from failed writes due to throttling. See http://doc.akka.io/docs/akka/snapshot/scala/io-tcp.html#throttling-reads-and-writes. So it's not necessarily disconnection.