title: Concurrency errors when using scala iterators in gatling
body: <p>I'm using gatling to run load tests. I'm not a gatling or scala expert, but it seems to me that this particular problem might be more related to scala (and Akka) than to gatling itself. I'll start at the end: When running at high load on a not-so-strong machine, I occasionally get this error: </p>
  
  <blockquote>
    <p>07:04:42.071 [ERROR]
    i.g.c.a.b.SessionHookBuilder$$anonfun$build$1$$anon$1 -
    'sessionHook-29' crashed on session
    Session(searchOrder,5348761459522421680-8295,Map(),1433329482056,0,
    OK,List(),), forwarding to the next one
    java.lang.UnsupportedOperationException: tail of empty list
            at scala.collection.immutable.Nil$.tail(List.scala:422) ~[scala-library-2.11.6.jar:na]
            at scala.collection.immutable.Nil$.tail(List.scala:417) ~[scala-library-2.11.6.jar:na]
            at scala.collection.LinearSeqLike$$anon$1.next(LinearSeqLike.scala:46)
    ~[scala-library-2.11.6.jar:na]
            at scala.collection.TraversableOnce$FlattenOps$$anon$1.next(TraversableOnce.scala:450)
    ~[scala-library-2.11.6.jar:na]
            at MyNamespace.Tenants$.next(Tenants.scala:21) ~[na:na]
            at MyNamespace.LoadTests$$anonfun$run$1.apply(LoadTests.scala:43)
    ~[na:na]
            at MyNamespace.LoadTests$$anonfun$run$1.apply(LoadTests.scala:41)
    ~[na:na]
            at io.gatling.core.action.SessionHook.executeOrFail(SessionHook.scala:35)
    ~[gatling-core-2.1.5.jar:2.1.5]
            at io.gatling.core.action.Failable$class.execute(Actions.scala:71)
    ~[gatling-core-2.1.5.jar:2.1.5]
            at io.gatling.core.action.SessionHook.execute(SessionHook.scala:28)
    ~[gatling-core-2.1.5.jar:2.1.5]
            at io.gatling.core.action.Action$$anonfun$receive$1.applyOrElse(Actions.scala:29)
    ~[gatling-core-2.1.5.jar:2.1.5]
            at scala.PartialFunction$OrElse.applyOrElse(PartialFunction.scala:171)
    ~[scala-library-2.11.6.jar:na]
            at akka.actor.Actor$class.aroundReceive(Actor.scala:465) ~[akka-actor_2.11-2.3.9.jar:na]
            at io.gatling.core.akka.BaseActor.aroundReceive(BaseActor.scala:22)
    ~[gatling-core-2.1.5.jar:2.1.5]
            at akka.actor.ActorCell.receiveMessage(ActorCell.scala:516) ~[akka-actor_2.11-2.3.9.jar:na]
            at akka.actor.ActorCell.invoke(ActorCell.scala:487) ~[akka-actor_2.11-2.3.9.jar:na]
            at akka.dispatch.Mailbox.processMailbox(Mailbox.scala:254) ~[akka-actor_2.11-2.3.9.jar:na]
            at akka.dispatch.Mailbox.run(Mailbox.scala:221) ~[akka-actor_2.11-2.3.9.jar:na]
            at akka.dispatch.Mailbox.exec(Mailbox.scala:231) ~[akka-actor_2.11-2.3.9.jar:na]
            at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260)
    ~[scala-library-2.11.6.jar:na]
            at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339)
    ~[scala-library-2.11.6.jar:na]
            at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979)
    [scala-library-2.11.6.jar:na]
            at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107)
    [scala-library-2.11.6.jar:na]</p>
  </blockquote>
  
  <p>I suspect it has to do with using </p>
  
  <pre><code>Iterator.continually([some collection]).flatten
  </code></pre>
  
  <p>where [some collection] is the collection that I'm trying to loop through circularly. Could it be that when lots of concurrent threads try to access an iterator defined in this way that it occasionally fails? Is there a better way to create a circular iterator that is also thread safe?</p>
  
  <p>As in the tenants object created by the "save" method below (in practice there is more code here that fills the collection retrieved by the get method, so it is actually never empty):</p>
  
  <pre><code>import io.gatling.core.Predef._
  
  object Tenants {
    type TenantKeys = Map[String, Map[String, String]]
    val key = "tenants"
    val elementKey = "tenant"
    var tenants: Iterator[Map[String, String]] = Iterator(Map[String, String]())
  
    def get(session: Session): TenantKeys = {
      session(key)
        .asOption[TenantKeys]
        .getOrElse(Map[String, Map[String, String]]())
    }
  
    def save(session: Session): Session = {
      val mapped = get(session).map(_._2).toSeq
      tenants = Iterator.continually(mapped).flatten
      session
    }
  }
  </code></pre>