• Gatling-插件开发



    源码

    参考:
    How to Write a Custom Protocol for Gatling?
    Creating a custom Gatling prococol for AWS Lambda

    插件开发

    Action

    package io.gatling.ext.redis.action
    
    import java.util.concurrent.Executors
    
    import com.typesafe.scalalogging.StrictLogging
    import io.gatling.commons.stats.{KO, OK}
    import io.gatling.commons.util.Clock
    import io.gatling.core.CoreComponents
    import io.gatling.core.action.{Action, ExitableAction}
    import io.gatling.core.session.{Expression, Session}
    import io.gatling.core.stats.StatsEngine
    import io.gatling.core.util.NameGen
    import io.gatling.ext.redis.protocol.RedisComponents
    import redis.clients.jedis.Jedis
    
    import scala.concurrent._
    import scala.util.{Failure, Success}
    
    
    class RedisGetAction(
                          key: Expression[String],
                          coreComponents: CoreComponents,
                          val redisComponents: RedisComponents,
                          throttled: Boolean,
                          val next: Action
                        ) extends ExitableAction with NameGen with StrictLogging {
    
      // 可以自定义也可以引入默认的执行器
      // import scala.concurrent.ExecutionContext.Implicits.global
      implicit val ec: ExecutionContextExecutor = ExecutionContext.fromExecutor(Executors.newFixedThreadPool(50))
    
      override def statsEngine: StatsEngine = coreComponents.statsEngine
    
      override def clock: Clock = coreComponents.clock
    
      override def name: String = genName("redis-get-action")
    
      override def execute(session: Session): Unit = {
    
        key(session) map {
    
          keyS => {
    
            val requestStartDate = clock.nowMillis
    
            val jedis: Jedis = redisComponents.jedisMap(session.userId)
    
            val future: Future[String] = Future[String] {
              jedis.get(keyS)
            }
    
            future onComplete {
              case Success(value) => statsEngine.logResponse(
                session,
                keyS,
                requestStartDate,
                clock.nowMillis,
                OK,
                Some(value),
                Some(value)
              )
              case Failure(exception) => {
                logger.error(exception.toString)
                statsEngine.logResponse(
                  session,
                  keyS,
                  requestStartDate,
                  clock.nowMillis,
                  KO,
                  Some(exception.getMessage),
                  Some(exception.getMessage)
                )
              }
            }
    
            if (throttled) {
              coreComponents.throttler.throttle(session.scenario, () => next ! session)
            } else {
              next ! session
            }
          }
        }
      }
    }
    

    ActionBuilder

    package io.gatling.ext.redis.builder
    
    import com.typesafe.scalalogging.StrictLogging
    import io.gatling.core.action.Action
    import io.gatling.core.action.builder.ActionBuilder
    import io.gatling.core.session.Expression
    import io.gatling.core.structure.ScenarioContext
    import io.gatling.ext.redis.action.RedisGetAction
    import io.gatling.ext.redis.protocol.RedisProtocol
    
    class RedisActionBuilder(key: Expression[String]) extends ActionBuilder with StrictLogging {
    
      override def build(ctx: ScenarioContext, next: Action): Action = {
    
        import ctx._
        new RedisGetAction(
          key,
          coreComponents,
          protocolComponentsRegistry.components(RedisProtocol.redisProtocolKey),
          throttled,
          next
        )
      }
    }
    

    Protocol & Components & Components

    package io.gatling.ext.redis.protocol
    
    import io.gatling.core.config.GatlingConfiguration
    import io.gatling.core.protocol.{Protocol, ProtocolComponents, ProtocolKey}
    import io.gatling.core.session.Session
    import io.gatling.core.{CoreComponents, protocol}
    import redis.clients.jedis.Jedis
    
    case class RedisProtocol(host: String, port: Int, password: Option[String]) extends Protocol {
      type Components = RedisComponents
    }
    
    object RedisProtocol {
    
      def apply(host: String, port: Int, password: Option[String] = None): RedisProtocol = new RedisProtocol(host, port, password)
    
      val redisProtocolKey: ProtocolKey[RedisProtocol, RedisComponents] = new ProtocolKey[RedisProtocol, RedisComponents] {
    
        override def protocolClass: Class[protocol.Protocol] = classOf[RedisProtocol].asInstanceOf[Class[io.gatling.core.protocol.Protocol]]
    
        override def defaultProtocolValue(configuration: GatlingConfiguration): RedisProtocol = RedisProtocol("127.0.0.1", 6379)
    
        override def newComponents(coreComponents: CoreComponents): RedisProtocol => RedisComponents = {
          redisProtocol => RedisComponents(redisProtocol)
        }
      }
    }
    
    case class RedisComponents(redisProtocol: RedisProtocol) extends ProtocolComponents {
    
      val jedisMap: scala.collection.mutable.Map[Long, Jedis] = scala.collection.mutable.HashMap()
    
      override def onStart: Session => Session = {
        session => {
          println("RedisComponents start: " + session)
          val jedis: Jedis = new Jedis(redisProtocol.host, redisProtocol.port)
    
          redisProtocol.password match {
            case Some(value) => jedis.auth(value)
            case None =>
          }
    
          jedis.set(String.valueOf(session.userId), session.toString)
    
          jedisMap(session.userId) = jedis
    
          session
        }
      }
    
      override def onExit: Session => Unit = {
        session => {
          println("RedisComponents exit: " + session)
        }
      }
    }
    
    case class RedisProtocolBuilder(host: String, port: Int, password: Option[String]) {
      def build: RedisProtocol = RedisProtocol(host, port, password)
    }
    
    object RedisProtocolBuilder {
      implicit def toRedisProtocol(builder: RedisProtocolBuilder): RedisProtocol = builder.build
    }
    

    Predef

    package io.gatling.ext.redis
    
    import io.gatling.core.session.Expression
    import io.gatling.ext.redis.builder.RedisActionBuilder
    import io.gatling.ext.redis.protocol.RedisProtocolBuilder
    
    object Predef {
    
      implicit def string2Option(string: String): Option[String] = Some(string)
      
      def redis(
                 host: String,
                 port: Int,
                 password: Option[String] = None
               ): RedisProtocolBuilder = RedisProtocolBuilder(host, port, password)
    
      def redis(key: Expression[String]): RedisActionBuilder = new RedisActionBuilder(key)
    }
    

    使用中遇到的问题

    如果要在DSL中使用hours、minutes等,需要导包:scala.concurrent.duration._
    Expression的本质是一个函数:session => type Expression[T] = Session => Validation[T]
    Validation中常用的两个函数:
    1. def map[A](f: T => A): Validation[A]
    2. def flatMap[A](f: T => Validation[A]): Validation[A]
  • 相关阅读:
    一个C++程序员学习C#语言
    C#入门教程笔记
    完全卸载mysql 停止服务、卸载相关程序、删除注册表
    C++结构简介
    babun,windows shell
    无限极设计以及随意移动节点(树结构)
    springboot 配置访问外部静态资源详解
    mysql8+keepalived 双主高可用搭建
    mysql 双主复制搭建
    mysql 主备搭建
  • 原文地址:https://www.cnblogs.com/CSunShine/p/12737746.html
Copyright © 2020-2023  润新知