加特林中的步骤是否已缓存并且只执行一次?

are Steps in gatling cached and only executed once?

我有一个模拟,其中包含一个允许我发布到不同端点的步骤。

class MySimulation extends Simulation {
  
  // some init code 

  var testTitle = this.getClass.getSimpleName
  
  val myscenario = scenario("Scn Description")
    .exec(PublishMessageRandom(pConfigTest, testTitle + "-" + numProducers, numProducers))   
  
  if (testMode == "debug") {
    setUp(
      myscenario.inject(
        atOnceUsers(1)
      )
    ).protocols(httpConf)    
  } else if (testMode == "open") {
    setUp(
      myscenario.inject(       
        rampConcurrentUsers(concurrentUserMin) to (concurrentUserMax) during (durationInMinutes minutes),
      )
    ).protocols(httpConf)
  }
}

现在这是我的PublishMessageRandom定义

def PublishMessageRandom(producerConfig : ProducerConfig, testTitle : String, numberOfProducers : Int ) = { 
      
      val jsonBody = producerConfig.asJson
      val valuedJsonBody = Printer.noSpaces.copy(dropNullValues = true).print(jsonBody)
      println(valuedJsonBody)
        
      val nodes : Array[String]  = endpoints.split(endpointDelimiter)
      val rnd = scala.util.Random
      val rndIndex = rnd.nextInt(numberOfProducers)      
      var endpoint = "http://" + nodes(rndIndex) + perfEndpoint      
      println("endpoint:" + endpoint)

      exec(http(testTitle)    
      .post(endpoint)    
      .header(HttpHeaderNames.ContentType, HttpHeaderValues.ApplicationJson)
      .body(StringBody(valuedJsonBody))
      .check(status.is(200))
      .check(bodyString.saveAs("serverResponse"))
    )
    // the below is only useful in debug mode. Comment it out for longer tests
    /*.exec { session =>
      println("server_response: " + session("serverResponse").as[String])
      println("endpoint:" + endpoint)
      session */
    }
  }

如您所见,它只是端点的循环。不幸的是,我看到上面的 println("endpoint:" + endpoint) 一次,它看起来像是随机选择一个端点并继续击中它,而不是随机击中端点的预期目的。

有人可以解释这种行为吗? Gatling 是在缓存 Step 还是我该如何绕过它?

引用官方documentation:

Warning

Gatling DSL components are immutable ActionBuilder(s) that have to be chained altogether and are only built once on startup. The results is a workflow chain of Action(s). These builders don’t do anything by themselves, they don’t trigger any side effect, they are just definitions. As a result, creating such DSL components at runtime in functions is completely meaningless.

我不得不使用feeder来解决feeder取随机端点的问题

  // feeder is random endpoint as per number of producers
  val endpointFeeder = GetEndpoints(numProducers).random
  
  val myscenario = scenario("Vary number of producers hitting Kafka cluster")
    .feed(endpointFeeder)
    .exec(PublishMessageRandom(pConfigTest, testTitle + "-" + numProducers))  

并随机发布消息如下所示:

def PublishMessageRandom(producerConfig : ProducerConfig, testTitle : String ) = { 
      
      val jsonBody = producerConfig.asJson
      val valuedJsonBody = Printer.noSpaces.copy(dropNullValues = true).print(jsonBody)
      println(valuedJsonBody)        
     
      exec(http(testTitle)    
      .post("${endpoint}")
      .header(HttpHeaderNames.ContentType, HttpHeaderValues.ApplicationJson)
      .body(StringBody(valuedJsonBody))
      .check(status.is(200))
      .check(bodyString.saveAs("serverResponse"))
    )

  }

你看到上面的线 .post("${endpoint}") 最终会到达来自馈线的端点。

feeder函数GetEndpoints定义如下 我们在其中创建一组具有一个值的映射,每个“端点”都是键。

 def GetEndpoints(numberOfProducers : Int ) : Array[Map[String,String]] = {  
      val nodes : Array[String]  = endpoints.split(endpointDelimiter)        
      var result : Array[Map[String,String]] = Array()
      for( elt <- 1 to numberOfProducers ) {   
        var endpoint = "http://" + nodes(elt-1) + perfEndpoint      
        var m : Map[String, String] = Map()
        m += ("endpoint" -> endpoint )
        result = result :+ m  
        println("map:" + m)    
      }
      result
  }