<commit_before>---
layout: docs.hbs
title: Routers
---

# Routers

A *router* is a special type of actor whose job is to route messages to other actors called *routees*. Different routers use different *strategies* to route messages efficiently.

Routers can be used inside or outside of an actor, and you can manage the routees yourself or use a self contained router actor with configuration capabilities, and can also [resize dynamically](#dynamically-resizable-pools) under load.

Akka.NET comes with several useful routers you can choose right out of the box, according to your application's needs. But it is also possible to create your own.

> **Note:**<br/>
> In general, any message sent to a router will be forwarded to one of its routees, but there is one exception.
> The special [Broadcast Message](#broadcast-messages) will be sent to all routees. See [Specially Handled Messages](#specially-handled-messages) section for details.

## Deployment

Routers can be deployed in multiple ways, using code or configuration.

#### Code deployment

The example below shows how to deploy 5 workers using a round robin router:

```cs
var props = Props.Create<Worker>().WithRouter(new RoundRobinPool(5));
var actor = system.ActorOf(props, "worker");
```

It's important to understand that although you create the Props and add the router later, the deployment happens in reverse order, with the workers being added to the router.
The above code can also be written as:

```cs
var props = new RoundRobinPool(5).Props(Props.Create<Worker>());
```

#### Configuration deployment

The same router may be defined using a [HOCON deployment configuration](../concepts/Configuration).

In order to do that, define a HOCON section with the path of the actor, and create the actor in that path using `FromConfig.Instance`.

```hocon
akka.actor.deployment {
  /workers {
    router = round-robin-pool
    nr-of-instances = 5
  }
}
```
```cs
var props = Props.Create<Worker>().WithRouter(FromConfig.Instance);
var actor = system.ActorOf(props, "workers");
```

For router groups, the same idea applies with slightly different syntax:

```hocon
akka.actor.deployment {
  /workers {
    router = round-robin-group
    routees.paths = ["/user/workers/w1", "/user/workers/w2", "/user/workers/w3"]
  }
}
```
```cs
var props = Props.Create<Worker>().WithRouter(FromConfig.Instance);
var actor = system.ActorOf(props, "workers");
```

As you can see above, the advantage of using HOCON for routers is that you can change the deployment of routers easily without recompiling the code.

## Pools vs. Groups

There are two types of routers:

* **Pools**

  Router "Pools" are routers that create their own worker actors, that is; you provide the *number of instances* as a parameter to the router and the router will handle routee creation by itself.

* **Groups**

  Sometimes, rather than having the router actor create its routees, it is desirable to create routees yourself and provide them to the router for its use. You can do this by passing the paths of the routees to the router's configuration. Messages will be sent with `ActorSelection` to these paths.

> **Note:**<br />
> Most routing strategies listed below are available in both types. Some of them may be available only in one type due to implementation requirements.

#### Supervision

Routers are implemented as actors, so a router is supervised by it's parent, and they may supervise children.

*Group routers* use routees created somewhere else, it doesn't have children of its own. If a routee dies, a group router will have no knowledge of it.

*Pool routers* on the other hand create their own children. The router is therefore also the routee's supervisor.

By default, pool routers use a custom strategy that only returns `Escalate` for all exceptions, the router supervising the failing worker will then escalate to it's own parent, if the parent of the router decides to restart the router, all the pool workers will also be recreated as a result of this.

## Routing Strategies

These are the routing strategies provided by Akka.NET out of the box.

### RoundRobin

`RoundRobinPool` and `RoundRobinGroup` are routers that sends messages to routees in [round-robin](http://en.wikipedia.org/wiki/Round-robin) order. It's the simplest way to distribute messages to multiple worker actors, on a best-effort basis.

![Round Robin Router](../images/RoundRobinRouter.png)

#### Usage:

RoundRobinPool defined in configuration:

```hocon
akka.actor.deployment {
  /some-pool {
    router = round-robin-pool
    nr-of-instances = 5
  }
}
```
```cs
var router = system.ActorOf(Props.Create<Worker>().WithRouter(FromConfig.Instance), "some-pool");
```

RoundRobinPool defined in code:

```cs
var router = system.ActorOf(Props.Create<Worker>().WithRouter(new RoundRobinPool(5)), "some-pool");
```

RoundRobinGroup defined in configuration:

```hocon
akka.actor.deployment {
  /some-group {
    router = round-robin-group
    routees.paths = ["/user/workers/w1", "/user/workers/w2", "/user/workers/w3"]
  }
}
```
```cs
var router = system.ActorOf(Props.Empty.WithRouter(FromConfig.Instance), "some-group");
```

RoundRobinGroup defined in code:

```cs
var workers = new [] { "/user/workers/w1", "/user/workers/w3", "/user/workers/w3" }
var router = system.ActorOf(Props.Empty.WithRouter(new RoundRobinGroup(workers)), "some-group");
```

### Broadcast

The `BroadcastPool` and `BroadcastGroup` routers will, as the name implies, broadcast any message to all of its routees.

![Broadcast Router](../images/BroadcastRouter.png)

#### Usage:

BroadcastPool defined in configuration:

```hocon
akka.actor.deployment {
  /some-pool {
    router = broadcast-pool
    nr-of-instances = 5
  }
}
```
```cs
var router = system.ActorOf(Props.Create<Worker>().WithRouter(FromConfig.Instance), "some-pool");
```

BroadcastPool defined in code:

```cs
var router = system.ActorOf(Props.Create<Worker>().WithRouter(new BroadcastPool(5)), "some-pool");
```

BroadcastGroup defined in configuration:

```hocon
akka.actor.deployment {
  /some-group {
    router = broadcast-group
    routees.paths = ["/user/a1", "/user/a2", "/user/a3"]
  }
}
```
```cs
var router = system.ActorOf(Props.Empty.WithRouter(FromConfig.Instance), "some-group");
```

BroadcastGroup defined in code:

```cs
var actors = new [] { "/user/a1", "/user/a2", "/user/a3" }
var router = system.ActorOf(Props.Empty.WithRouter(new BroadcastGroup(actors)), "some-group");
```

### Random

The `RandomPool` and `RandomGroup` routers will forward messages to routees in random order.

#### Usage:

RandomPool defined in configuration:

```hocon
akka.actor.deployment {
  /some-pool {
    router = random-pool
    nr-of-instances = 5
  }
}
```
```cs
var router = system.ActorOf(Props.Create<Worker>().WithRouter(FromConfig.Instance), "some-pool");
```

RandomPool defined in code:

```cs
var router = system.ActorOf(Props.Create<Worker>().WithRouter(new RandomPool(5)), "some-pool");
```

RandomGroup defined in configuration:

```hocon
akka.actor.deployment {
  /some-group {
    router = random-group
    routees.paths = ["/user/workers/w1", "/user/workers/w2", "/user/workers/w3"]
  }
}
```
```cs
var router = system.ActorOf(Props.Empty.WithRouter(FromConfig.Instance), "some-group");
```

RandomGroup defined in code:

```cs
var workers = new [] { "/user/workers/w1", "/user/workers/w3", "/user/workers/w3" }
var router = system.ActorOf(Props.Empty.WithRouter(new RandomGroup(workers)), "some-group");
```

### ConsistentHashing

The `ConsistentHashingPool` and `ConsistentHashingGroup` are routers that use a [consistent hashing algorithm](http://en.wikipedia.org/wiki/Consistent_hashing) to select a routee to forward the message. The idea is that messages with the same key are forwarded to the same routee. Any .NET object can be used as a key, although it's usually a number, string or Guid.

![ConsistentHash Router](../images/ConsistentHashRouter.png)

`ConsistentHash` can be very useful when dealing with **Commands** in the sense of [**CQRS**](http://en.wikipedia.org/wiki/Command%E2%80%93query_separation#Command_Query_Responsibility_Segregation) or [**Domain Driven Design**].

For example, let's assume we have the following incoming sequence of **"Customer Commands"**:

![ConsistentHash Router example](../images/ConsistentHash1.png)

In this case we might want to group all messages based on **"Customer ID"** (ID in the diagram).

By using a `ConsistentHash` router we can now process multiple commands in parallel for different Customers, while still processing messages for each specific Customer in ordered sequence, and thus preventing us from getting race conditions with ourselves when applying each command on each customer entity.

![ConsistentHash Router example](../images/ConsistentHash2.png)

There are 3 ways to define what data to use for the consistent hash key.

1. You can define a *hash mapping delegate* using the `WithHashMapper` method of the router to map incoming messages to their consistent hash key. This makes the decision transparent for the sender.
```cs
  new ConsistentHashingPool(5).WithHashMapping(o =>
  {
      if (o is IHasCustomKey)
          return ((IHasCustomKey)o).Key;

      return null;
  });
```

2. The messages may implement `IConsistentHashable`. The key is part of the message and it's convenient to define it together with the message definition.
```cs
  public class SomeMessage : IConsistentHashable
  {
      public Guid GroupID { get; private set; }
      public object ConsistentHashKey {  get { return GroupID; } }
  }
```

3. The messages can be wrapped in a `ConsistentHashableEnvelope` to define what data to use for the consistent hash key. The sender knows the key to use.
```cs
  public class SomeMessage
  {
     public Guid GroupID { get; set; }
  }

  var originalMsg = new SomeMessage { GroupID = Guid.NewGuid(); };
  var msg = new ConsistentHashableEnvelope(originalMsg, originalMsg.GroupID);
```

You may implement more than one hashing mechanism at the same time. Akka.NET will try them in the order above. That is, if the HashMapping method returns null, Akka.NET will check for the IConsistentHashable interface in the message (2 and 3 are technically the same).

#### Usage:

ConsistentHashingPool defined in configuration:

```hocon
akka.actor.deployment {
  /some-pool {
    router = consistent-hashing-pool
    nr-of-instances = 5
    virtual-nodes-factor = 10
  }
}
```
```cs
var router = system.ActorOf(Props.Create<Worker>().WithRouter(FromConfig.Instance), "some-pool");
```

ConsistentHashingPool defined in code:

```cs
var router = system.ActorOf(Props.Create<Worker>().WithRouter(new ConsistentHashingPool(5)), "some-pool");
```

ConsistentHashingGroup defined in configuration:

```hocon
akka.actor.deployment {
  /some-group {
    router = consistent-hashing-group
    routees.paths = ["/user/workers/w1", "/user/workers/w2", "/user/workers/w3"]
    virtual-nodes-factor = 10
  }
}
```
```cs
var router = system.ActorOf(Props.Empty.WithRouter(FromConfig.Instance), "some-group");
```

ConsistentHashingGroup defined in code:

```cs
var workers = new [] { "/user/workers/w1", "/user/workers/w3", "/user/workers/w3" }
var router = system.ActorOf(Props.Empty.WithRouter(new ConsistentHashingGroup(workers)), "some-group");
```

> **Notes:**<br>
> 1. `virtual-nodes-factor` is the number of virtual nodes per routee that is used in the consistent hash node ring - if not defined, the default value is 10 and you shouldn't need to change it unless you understand how the algorithm works and know what you are doing.
> 2. It is possible to define this value in code using the `WithVirtualFactor(...)` method of the ConsistentHashingPool/Group object.

### TailChopping

The `TailChoppingPool` and `TailChoppingGroup` routers send the message to a random routee, and if no response is received after a specified delay, send it to another randomly selected routee. It waits for the first reply from any of the routees, and forwards it back to the original sender. Other replies are discarded. If no reply is received after a specified interval, a timeout Failure is generated.

The goal of this router is to decrease latency by performing redundant queries to multiple routees, assuming that one of the other actors may still be faster to respond than the initial one.

This optimization was described nicely in a blog post by <NAME>: [Doing redundant work to speed up distributed queries](http://www.bailis.org/blog/doing-redundant-work-to-speed-up-distributed-queries/).

#### Usage:

TailChoppingPool defined in configuration:

```hocon
akka.actor.deployment {
  /some-pool {
    router = tail-chopping-pool
    nr-of-instances = 5
    within = 10 seconds
    tail-chopping-router.interval = 20 milliseconds
  }
}
```
```cs
var router = system.ActorOf(Props.Create<Worker>().WithRouter(FromConfig.Instance), "some-pool");
```

TailChoppingPool defined in code:

```cs
var within = TimeSpan.FromSeconds(10);
var interval = TimeSpan.FromMilliseconds(20);
var router = system.ActorOf(Props.Create<Worker>().WithRouter(new TailChoppingPool(5, within, interval)), "some-pool");
```

TailChoppingGroup defined in configuration:

```hocon
akka.actor.deployment {
  /some-group {
    router = tail-chopping-group
    routees.paths = ["/user/workers/w1", "/user/workers/w2", "/user/workers/w3"]
    within = 10 seconds
    tail-chopping-router.interval = 20 milliseconds
  }
}
```
```cs
var router = system.ActorOf(Props.Empty.WithRouter(FromConfig.Instance), "some-group");
```

TailChoppingGroup defined in code:

```cs
var workers = new [] { "/user/workers/w1", "/user/workers/w3", "/user/workers/w3" }
var within = TimeSpan.FromSeconds(10);
var interval = TimeSpan.FromMilliseconds(20);
var router = system.ActorOf(Props.Empty.WithRouter(new TailChoppingGroup(workers, within, interval)), "some-group");
```

> **Notes:**<br />
> 1. `within` is the time to wait for a reply from any routee before timing out
> 2. `tail-chopping-router.interval` is the interval between requests to the other routees

### ScatterGatherFirstCompleted

The `ScatterGatherFirstCompletedPool` and `ScatterGatherFirstCompletedRouter` routers will broadcast the message to all routees and reply back to the original sender with the first reply it receives. All other replies are discarded. If no reply is received after a specified interval, a timeout Failure is generated.

This is useful in scenarios where you can accept any reply to a query and doesn't care who answers (eg. you may query multiple servers in a cluster just to know if any of them is online - if one answers, you may not care about the others).

![ScatterGatherFirstCompleted Router](../images/ScatterGatherFirstCompletedRouter.png)

#### Usage:

ScatterGatherFirstCompletedPool defined in configuration:

```hocon
akka.actor.deployment {
  /some-pool {
    router = scatter-gather-pool
    nr-of-instances = 5
    within = 10 seconds
  }
}
```
```cs
var router = system.ActorOf(Props.Create<Worker>().WithRouter(FromConfig.Instance), "some-pool");
```

ScatterGatherFirstCompletedPool defined in code:

```cs
var within = TimeSpan.FromSeconds(10);
var router = system.ActorOf(Props.Create<Worker>().WithRouter(new ScatterGatherFirstCompletedPool(5, within)), "some-pool");
```

ScatterGatherFirstCompletedPool defined in configuration:

```hocon
akka.actor.deployment {
  /some-group {
    router = scatter-gather-group
    routees.paths = ["/user/workers/w1", "/user/workers/w2", "/user/workers/w3"]
    within = 10 seconds
  }
}
```
```cs<commit_msg>fix Router documentation to accurately reflect hocon parsing in GetTimeSpan method<commit_after>---
layout: docs.hbs
title: Routers
---

# Routers

A *router* is a special type of actor whose job is to route messages to other actors called *routees*. Different routers use different *strategies* to route messages efficiently.

Routers can be used inside or outside of an actor, and you can manage the routees yourself or use a self contained router actor with configuration capabilities, and can also [resize dynamically](#dynamically-resizable-pools) under load.

Akka.NET comes with several useful routers you can choose right out of the box, according to your application's needs. But it is also possible to create your own.

> **Note:**<br/>
> In general, any message sent to a router will be forwarded to one of its routees, but there is one exception.
> The special [Broadcast Message](#broadcast-messages) will be sent to all routees. See [Specially Handled Messages](#specially-handled-messages) section for details.

## Deployment

Routers can be deployed in multiple ways, using code or configuration.

#### Code deployment

The example below shows how to deploy 5 workers using a round robin router:

```cs
var props = Props.Create<Worker>().WithRouter(new RoundRobinPool(5));
var actor = system.ActorOf(props, "worker");
```

It's important to understand that although you create the Props and add the router later, the deployment happens in reverse order, with the workers being added to the router.
The above code can also be written as:

```cs
var props = new RoundRobinPool(5).Props(Props.Create<Worker>());
```

#### Configuration deployment

The same router may be defined using a [HOCON deployment configuration](../concepts/Configuration).

In order to do that, define a HOCON section with the path of the actor, and create the actor in that path using `FromConfig.Instance`.

```hocon
akka.actor.deployment {
  /workers {
    router = round-robin-pool
    nr-of-instances = 5
  }
}
```
```cs
var props = Props.Create<Worker>().WithRouter(FromConfig.Instance);
var actor = system.ActorOf(props, "workers");
```

For router groups, the same idea applies with slightly different syntax:

```hocon
akka.actor.deployment {
  /workers {
    router = round-robin-group
    routees.paths = ["/user/workers/w1", "/user/workers/w2", "/user/workers/w3"]
  }
}
```
```cs
var props = Props.Create<Worker>().WithRouter(FromConfig.Instance);
var actor = system.ActorOf(props, "workers");
```

As you can see above, the advantage of using HOCON for routers is that you can change the deployment of routers easily without recompiling the code.

## Pools vs. Groups

There are two types of routers:

* **Pools**

  Router "Pools" are routers that create their own worker actors, that is; you provide the *number of instances* as a parameter to the router and the router will handle routee creation by itself.

* **Groups**

  Sometimes, rather than having the router actor create its routees, it is desirable to create routees yourself and provide them to the router for its use. You can do this by passing the paths of the routees to the router's configuration. Messages will be sent with `ActorSelection` to these paths.

> **Note:**<br />
> Most routing strategies listed below are available in both types. Some of them may be available only in one type due to implementation requirements.

#### Supervision

Routers are implemented as actors, so a router is supervised by it's parent, and they may supervise children.

*Group routers* use routees created somewhere else, it doesn't have children of its own. If a routee dies, a group router will have no knowledge of it.

*Pool routers* on the other hand create their own children. The router is therefore also the routee's supervisor.

By default, pool routers use a custom strategy that only returns `Escalate` for all exceptions, the router supervising the failing worker will then escalate to it's own parent, if the parent of the router decides to restart the router, all the pool workers will also be recreated as a result of this.

## Routing Strategies

These are the routing strategies provided by Akka.NET out of the box.

### RoundRobin

`RoundRobinPool` and `RoundRobinGroup` are routers that sends messages to routees in [round-robin](http://en.wikipedia.org/wiki/Round-robin) order. It's the simplest way to distribute messages to multiple worker actors, on a best-effort basis.

![Round Robin Router](../images/RoundRobinRouter.png)

#### Usage:

RoundRobinPool defined in configuration:

```hocon
akka.actor.deployment {
  /some-pool {
    router = round-robin-pool
    nr-of-instances = 5
  }
}
```
```cs
var router = system.ActorOf(Props.Create<Worker>().WithRouter(FromConfig.Instance), "some-pool");
```

RoundRobinPool defined in code:

```cs
var router = system.ActorOf(Props.Create<Worker>().WithRouter(new RoundRobinPool(5)), "some-pool");
```

RoundRobinGroup defined in configuration:

```hocon
akka.actor.deployment {
  /some-group {
    router = round-robin-group
    routees.paths = ["/user/workers/w1", "/user/workers/w2", "/user/workers/w3"]
  }
}
```
```cs
var router = system.ActorOf(Props.Empty.WithRouter(FromConfig.Instance), "some-group");
```

RoundRobinGroup defined in code:

```cs
var workers = new [] { "/user/workers/w1", "/user/workers/w3", "/user/workers/w3" }
var router = system.ActorOf(Props.Empty.WithRouter(new RoundRobinGroup(workers)), "some-group");
```

### Broadcast

The `BroadcastPool` and `BroadcastGroup` routers will, as the name implies, broadcast any message to all of its routees.

![Broadcast Router](../images/BroadcastRouter.png)

#### Usage:

BroadcastPool defined in configuration:

```hocon
akka.actor.deployment {
  /some-pool {
    router = broadcast-pool
    nr-of-instances = 5
  }
}
```
```cs
var router = system.ActorOf(Props.Create<Worker>().WithRouter(FromConfig.Instance), "some-pool");
```

BroadcastPool defined in code:

```cs
var router = system.ActorOf(Props.Create<Worker>().WithRouter(new BroadcastPool(5)), "some-pool");
```

BroadcastGroup defined in configuration:

```hocon
akka.actor.deployment {
  /some-group {
    router = broadcast-group
    routees.paths = ["/user/a1", "/user/a2", "/user/a3"]
  }
}
```
```cs
var router = system.ActorOf(Props.Empty.WithRouter(FromConfig.Instance), "some-group");
```

BroadcastGroup defined in code:

```cs
var actors = new [] { "/user/a1", "/user/a2", "/user/a3" }
var router = system.ActorOf(Props.Empty.WithRouter(new BroadcastGroup(actors)), "some-group");
```

### Random

The `RandomPool` and `RandomGroup` routers will forward messages to routees in random order.

#### Usage:

RandomPool defined in configuration:

```hocon
akka.actor.deployment {
  /some-pool {
    router = random-pool
    nr-of-instances = 5
  }
}
```
```cs
var router = system.ActorOf(Props.Create<Worker>().WithRouter(FromConfig.Instance), "some-pool");
```

RandomPool defined in code:

```cs
var router = system.ActorOf(Props.Create<Worker>().WithRouter(new RandomPool(5)), "some-pool");
```

RandomGroup defined in configuration:

```hocon
akka.actor.deployment {
  /some-group {
    router = random-group
    routees.paths = ["/user/workers/w1", "/user/workers/w2", "/user/workers/w3"]
  }
}
```
```cs
var router = system.ActorOf(Props.Empty.WithRouter(FromConfig.Instance), "some-group");
```

RandomGroup defined in code:

```cs
var workers = new [] { "/user/workers/w1", "/user/workers/w3", "/user/workers/w3" }
var router = system.ActorOf(Props.Empty.WithRouter(new RandomGroup(workers)), "some-group");
```

### ConsistentHashing

The `ConsistentHashingPool` and `ConsistentHashingGroup` are routers that use a [consistent hashing algorithm](http://en.wikipedia.org/wiki/Consistent_hashing) to select a routee to forward the message. The idea is that messages with the same key are forwarded to the same routee. Any .NET object can be used as a key, although it's usually a number, string or Guid.

![ConsistentHash Router](../images/ConsistentHashRouter.png)

`ConsistentHash` can be very useful when dealing with **Commands** in the sense of [**CQRS**](http://en.wikipedia.org/wiki/Command%E2%80%93query_separation#Command_Query_Responsibility_Segregation) or [**Domain Driven Design**].

For example, let's assume we have the following incoming sequence of **"Customer Commands"**:

![ConsistentHash Router example](../images/ConsistentHash1.png)

In this case we might want to group all messages based on **"Customer ID"** (ID in the diagram).

By using a `ConsistentHash` router we can now process multiple commands in parallel for different Customers, while still processing messages for each specific Customer in ordered sequence, and thus preventing us from getting race conditions with ourselves when applying each command on each customer entity.

![ConsistentHash Router example](../images/ConsistentHash2.png)

There are 3 ways to define what data to use for the consistent hash key.

1. You can define a *hash mapping delegate* using the `WithHashMapper` method of the router to map incoming messages to their consistent hash key. This makes the decision transparent for the sender.
```cs
  new ConsistentHashingPool(5).WithHashMapping(o =>
  {
      if (o is IHasCustomKey)
          return ((IHasCustomKey)o).Key;

      return null;
  });
```

2. The messages may implement `IConsistentHashable`. The key is part of the message and it's convenient to define it together with the message definition.
```cs
  public class SomeMessage : IConsistentHashable
  {
      public Guid GroupID { get; private set; }
      public object ConsistentHashKey {  get { return GroupID; } }
  }
```

3. The messages can be wrapped in a `ConsistentHashableEnvelope` to define what data to use for the consistent hash key. The sender knows the key to use.
```cs
  public class SomeMessage
  {
     public Guid GroupID { get; set; }
  }

  var originalMsg = new SomeMessage { GroupID = Guid.NewGuid(); };
  var msg = new ConsistentHashableEnvelope(originalMsg, originalMsg.GroupID);
```

You may implement more than one hashing mechanism at the same time. Akka.NET will try them in the order above. That is, if the HashMapping method returns null, Akka.NET will check for the IConsistentHashable interface in the message (2 and 3 are technically the same).

#### Usage:

ConsistentHashingPool defined in configuration:

```hocon
akka.actor.deployment {
  /some-pool {
    router = consistent-hashing-pool
    nr-of-instances = 5
    virtual-nodes-factor = 10
  }
}
```
```cs
var router = system.ActorOf(Props.Create<Worker>().WithRouter(FromConfig.Instance), "some-pool");
```

ConsistentHashingPool defined in code:

```cs
var router = system.ActorOf(Props.Create<Worker>().WithRouter(new ConsistentHashingPool(5)), "some-pool");
```

ConsistentHashingGroup defined in configuration:

```hocon
akka.actor.deployment {
  /some-group {
    router = consistent-hashing-group
    routees.paths = ["/user/workers/w1", "/user/workers/w2", "/user/workers/w3"]
    virtual-nodes-factor = 10
  }
}
```
```cs
var router = system.ActorOf(Props.Empty.WithRouter(FromConfig.Instance), "some-group");
```

ConsistentHashingGroup defined in code:

```cs
var workers = new [] { "/user/workers/w1", "/user/workers/w3", "/user/workers/w3" }
var router = system.ActorOf(Props.Empty.WithRouter(new ConsistentHashingGroup(workers)), "some-group");
```

> **Notes:**<br>
> 1. `virtual-nodes-factor` is the number of virtual nodes per routee that is used in the consistent hash node ring - if not defined, the default value is 10 and you shouldn't need to change it unless you understand how the algorithm works and know what you are doing.
> 2. It is possible to define this value in code using the `WithVirtualFactor(...)` method of the ConsistentHashingPool/Group object.

### TailChopping

The `TailChoppingPool` and `TailChoppingGroup` routers send the message to a random routee, and if no response is received after a specified delay, send it to another randomly selected routee. It waits for the first reply from any of the routees, and forwards it back to the original sender. Other replies are discarded. If no reply is received after a specified interval, a timeout Failure is generated.

The goal of this router is to decrease latency by performing redundant queries to multiple routees, assuming that one of the other actors may still be faster to respond than the initial one.

This optimization was described nicely in a blog post by <NAME>: [Doing redundant work to speed up distributed queries](http://www.bailis.org/blog/doing-redundant-work-to-speed-up-distributed-queries/).

#### Usage:

TailChoppingPool defined in configuration:

```hocon
akka.actor.deployment {
  /some-pool {
    router = tail-chopping-pool
    nr-of-instances = 5
    within = 10s
    tail-chopping-router.interval = 20ms
  }
}
```
```cs
var router = system.ActorOf(Props.Create<Worker>().WithRouter(FromConfig.Instance), "some-pool");
```

TailChoppingPool defined in code:

```cs
var within = TimeSpan.FromSeconds(10);
var interval = TimeSpan.FromMilliseconds(20);
var router = system.ActorOf(Props.Create<Worker>().WithRouter(new TailChoppingPool(5, within, interval)), "some-pool");
```

TailChoppingGroup defined in configuration:

```hocon
akka.actor.deployment {
  /some-group {
    router = tail-chopping-group
    routees.paths = ["/user/workers/w1", "/user/workers/w2", "/user/workers/w3"]
    within = 10s
    tail-chopping-router.interval = 20ms
  }
}
```
```cs
var router = system.ActorOf(Props.Empty.WithRouter(FromConfig.Instance), "some-group");
```

TailChoppingGroup defined in code:

```cs
var workers = new [] { "/user/workers/w1", "/user/workers/w3", "/user/workers/w3" }
var within = TimeSpan.FromSeconds(10);
var interval = TimeSpan.FromMilliseconds(20);
var router = system.ActorOf(Props.Empty.WithRouter(new TailChoppingGroup(workers, within, interval)), "some-group");
```

> **Notes:**<br />
> 1. `within` is the time to wait for a reply from any routee before timing out
> 2. `tail-chopping-router.interval` is the interval between requests to the other routees

### ScatterGatherFirstCompleted

The `ScatterGatherFirstCompletedPool` and `ScatterGatherFirstCompletedRouter` routers will broadcast the message to all routees and reply back to the original sender with the first reply it receives. All other replies are discarded. If no reply is received after a specified interval, a timeout Failure is generated.

This is useful in scenarios where you can accept any reply to a query and doesn't care who answers (eg. you may query multiple servers in a cluster just to know if any of them is online - if one answers, you may not care about the others).

![ScatterGatherFirstCompleted Router](../images/ScatterGatherFirstCompletedRouter.png)

#### Usage:

ScatterGatherFirstCompletedPool defined in configuration:

```hocon
akka.actor.deployment {
  /some-pool {
    router = scatter-gather-pool
    nr-of-instances = 5
    within = 10s
  }
}
```
```cs
var router = system.ActorOf(Props.Create<Worker>().WithRouter(FromConfig.Instance), "some-pool");
```

ScatterGatherFirstCompletedPool defined in code:

```cs
var within = TimeSpan.FromSeconds(10);
var router = system.ActorOf(Props.Create<Worker>().WithRouter(new ScatterGatherFirstCompletedPool(5, within)), "some-pool");
```

ScatterGatherFirstCompletedPool defined in configuration:

```hocon
akka.actor.deployment {
  /some-group {
    router = scatter-gather-group
    routees.paths = ["/user/workers/w1", "/user/workers/w2", "/user/workers/w3"]
    within = 10s
  }
}
```
```cs
{'fraction_non_alphanumeric': 0.11309504728321847, 'fraction_numerical': 0.006283058182401026, 'mean_word_length': 4.549902152641879, 'pattern_counts': {'":': 0, '<': 45, '<?xml version=': 0, '>': 69, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6188058', 'n_tokens_mistral': 9402, 'n_tokens_neox': 8986, 'n_words': 3357}