Switching policies

rezilience policies can be switched at runtime to modify policy characteristics.

Example

import zio._
import nl.vroste.rezilience._

val initialPolicy: ZManaged[Clock, Nothing, Policy[Any]] = RateLimiter.make(1, 1.seconds).map(_.toPolicy)
val newPolicy: ZManaged[Clock, Nothing, Policy[Any]] = RateLimiter.make(10, 1.seconds).map(_.toPolicy)

val policy: ZManaged[Clock, Nothing, SwitchablePolicy[Any]] = 
  SwitchablePolicy.make(initialPolicy)

policy.use { policy =>
  for {
    _ <- policy.apply(ZIO.effect("Something"))
    switchComplete <- policy.switch(newPolicy, mode = SwitchablePolicy.Mode.Transition)
    
    // At this moment, any new calls will run with the new policy
    // Optionally you can await the release of the old policy:
    // _ <- switchComplete
    _ <- policy.apply(ZIO.effect("Something else"))
  } yield ()
}

Behavior

Policies can be switched with two modes:

  • Transition
    Process new calls with the new policies while allowing in-flight calls to finish with the old policy.
  • Finish In-Flight
    Hold new calls until all in-flight calls have completed.

By working with ZManageds of Policy, policies can be released and switched in a controlled manner.

Like all other policies, a call made with a SwitchablePolicy can be interrupted safely, also while a policy switch is in flight.

Keep in mind the effect of switching mode for different policies. As an example, consider switching a RateLimiter policy from 10 calls per second to 20 calls per second where the average call takes more than 100 ms. In FinishInFlight mode, the effective rate during the switch will be less than 10, until all calls have completed. Also there may be a spike when the new rate begins with 20. In Transition mode, the effective rate may be higher than 20.