Skip to main content

Posts

Showing posts from July, 2013

Asynchronous retry pattern

When you have a piece of code that often fails and must be retried, this Java 7/8 library provides rich and unobtrusive API with fast and scalable solution to this problem:

ScheduledExecutorService scheduler = Executors.newSingleThreadScheduledExecutor(); RetryExecutor executor = new AsyncRetryExecutor(scheduler). retryOn(SocketException.class). withExponentialBackoff(500, 2). //500ms times 2 after each retry withMaxDelay(10_000). //10 seconds withUniformJitter(). //add between +/- 100 ms randomly withMaxRetries(20); You can now run arbitrary block of code and the library will retry it for you in case it throws SocketException:

final CompletableFuture<Socket> future = executor.getWithRetry(() -> new Socket("localhost", 8080) ); future.thenAccept(socket -> System.out.println("Connected! " + socket) ); Please look carefully! getWithRetry() does not block. It returns CompletableFuture i…

Managing congested actors in Akka

There comes a time in an Akka application when an actor can longer handle increasing load. Since each actor can only handle one message at a time and it keeps a backlog of pending messages in a queue called mailbox, there is a risk of overloading one actor if too many messages are sent to one actor at the same time or actor fails to process messages fast enough - queue will keep growing and growing. This will negatively impact responsiveness of the system and might even result in application crashing.

It’s actually very easy to simulate such load by simply sending continuous stream of messages to an actor as fast as possible:

case object Ping class PingActor extends Actor { def receive = { case Ping => //don't do this at home! Thread sleep 1 } } object Main extends App { val system = ActorSystem("Heavy") val client = system.actorOf(Props[PingActor], "Ping") while(true) { client ! Ping } } O…

Fake system clock pattern in Scala with implicit parameters

Fake system clock is a design pattern addressing testability issues of programs heavily relying on system time. If business logic flow depends on current system time, testing various flows becomes cumbersome or even impossible. Examples of such problematic scenarios include:

certain business flow runs only (or is ignored) during weekendssome logic is triggered only after an hour since some other eventwhen two events occur at the exact same time (typically 1 ms precision), something should happen… Each scenario above poses unique set of challenges. Taken literally our unit tests would have to run only on specific day (1) or sleep for an hour to observe some behaviour. Scenario (3) might even be impossible to test under some circumstances since system clock can tick 1 millisecond at any time, thus making test unreliable.

Fake system clock addresses these issues by abstracting system time over simple interface. Essentially you never call new Date(), new GregorianCalendar() or System.curre…

Macro lifecycle in Clojure

If you still struggle to understand what are macros in Clojure and why are they so useful, I will guide you through another example today. We will learn when macros are recognized, evaluated, expanded and executed. I believe the most important concept is their similarity to normal functions. As I described last time, macros are ordinary functions but executed at compile time and taking code rather than values as arguments. The second difference is slightly artificial since Clojure code is a value in sense that it can be passed around. So let us focus on when macros are actually expanded and executed.

We will start from trivial GCD implementation in Clojure as a normal function:

(defn gcd [a b] (if (zero? b) a (recur b (mod a b)))) Calling this function will result in a tail-recursive loop executed at runtime every time it is encountered:

user=> (gcd 18 12) 6 user=> (gcd 9 2) 1 user=> (gcd 9 (inc 2)) 3 Not very exciting. But what if we wrap reference to gc…