Websocket: cannot listen for pushed messages from the server if i have a running wsAwait with check

Hi There,

According to the documentation:
Gatling currently only support one check at a time per websocket.

If I set a check directly onto the websocket I could listen on every incoming messages but I cannot initiate a new sendTest with a check as it overrides the first one.
If I create a new check with sendText I cannot listen on other pushed messages from the server.
So as it is now it makes almost impossible to test a complex websocket application with request/response and pushed messages from the server especially when those requests depend on some pushed messages.

I would like to implement a cometd layer on top of the websocket module. But the current implementation prevents me to be able to implement publish/subscribe functionality as I cannot handle properly pushed messages.

The scenarios is the following:
I subscribe to a topic in the server which is going to push messages in regular time period. I would like to process those messages like saving data to session to drive synchronous request/responses with wsAwait.
I send commands based on the pushed messages and check the response.

Is there any way how I could handle request/response (wsAwait) and pushed messages (wsListen) paralel way?

Cheers,
krisztian

This is the first version of the API.
It already can do a lot, but I agree you can’t build very complex interaction.
Feel free to help designing a better WebSocket API for Gatling 2.1.

Cheers,

Stéphane

Hi Guys,

I was thinking about the solution.
I have 2 possible candidates but I would like to see which is feasible:

1: Modifying the DSL to be able pass an Actor class which is used under the hood to create an ActorRef via GatlingActorSystem and passed into the WsActor and can be used in the OnTextMessage as a kind of callback for every incoming messages. This actor could process any incoming messages despite the fact that what kind of check is registered if it is registered at all. It would be good for pushed messages from the server without having sent request and check. It is up to the implementor of the actor to process those passed messages behind the scene as he needs it. Later on in the doIf or exec method I could ask this actor to give back saved data for a normal wsAwait request what I could save to the session before send.

I like the idea that I could handle async messages from the server and it is not coupled to checks.

2: Because there is just one check at the time I could play with this registered checks.

  • If I have a wsAwait and check I add an extra transform method which passes every incoming messages to my actor for further processing. After that the normal transform method is coming which is responsible for the response handling for that specific request.
  • The bottleneck is the pause(…) method as during the pause there isn’t any check (if the previous call was a wsAwait). In this case I have to register a new check before calling the pause. I could add an extra pauseAndListen method using implicit conversion and before really call pause() I could call something like this:
    .exec(ws(“asynccheck”).check(wsListen.within(5 seconds).until(Range(0,1000)).message.transform(m => myActor ! Message(m) ))
    .pause(5 second)
    My main concern is that I have to have always a registered check to be able to process pushed messages. With this approach I always try to provide it.

If I have to choose I would go for the first solution but I need your opinion.

Many thanks,
Krisztian

Your first proposal is interesting, yet designing a convenient DSL that actually helps and can be used by most users is the most critical part.
Do you have any idea what your API would look like?

Hi Stephane,

Actually I have implemented my own version using implicit conversion and implicit classes. It is not so nice since I had to duplicate couple of classes but it proves that it could work.
the API is the following:

val processor = GatlingActorSystem.instance.actorOf(Processor.props, name = “Processor”)

object Processor {
def props: Props = Props[Processor]
}

class Processor extends Actor with ActorLogging {
override def receive: Actor.Receive = {

case message: String =>
log.info(message)
}
}

.exec(ws(“handshake”).open("/cometd/handshake").registerPushProcessor(processor))

Probably it is not the best method name for this but works and it would be good have a kind of basic actor type what you have to implement instead of using ActorRef directly. Using the actor ref has an advantage as I can ask it for extracted data like:

.exec(session => {
implicit val timeout = Timeout(5 seconds)
import akka.pattern.ask
val gameReference = processor ? GetGameReference
val result = Await.result(gameReference, timeout.duration).asInstanceOf[Option[String]]
if (result.isDefined)
session.set(“gameReference”, result.get)
else
session.remove(“gameReference”)
})

And based on the session:

.doIf(session => {
session.contains(“gameReference”)

}) {
exec(ws(“placeBet”).sendText(placeBet).checkResponse(commandCheck(_, “corId4”)))
}

And again I have to pass directly the validation data (corId4) which was sent in the request instead of being able to get it from the session directly (another raised issue…)

In the WsActor’s onMessage:

case OnTextMessage(message, time) =>
logger.debug(s"Received message on websocket ‘$wsName’:$message")

processor.foreach { processor =>
processor ! message
}

In nut shell this the implementation I have.
If you have any better advice. pls.

Cheers,
Krisztian

val result = Await.result(gameReference, timeout.duration).asInstanceOf[Option[String]]

Ouch! Await.result is blocking!!!

I know.
But I believe it couldn’t affect the background processor. On the other hand I need the information stored in the processor to decide if the simulation should call a specific exec method.

If I could update the session async way it won’t be blocking. But I cannot see any option for this.

k

Hi,

It there any better idea or suggestion for this?
Krisztian

Honestly, I won’t have time for this before starting working on Gatling 2.1.
I will ping you then.

Cheers,

Stéphane

Hi Guys,

I have been working on a cometD extension built on top of gatling 2 websocket .
Obviously there are much space for improvements and the DSL is still under development but you could still play around with it.
The project can be found on github and also available from sonatype although it has just a SNAPSHOT version so far.

https://github.com/lachatak/gatling-cometd
https://oss.sonatype.org/content/repositories/snapshots/org/kaloz/gatling/http-cometd/1.0.0-SNAPSHOT/

If you have any suggestions, ideas feel free to share.

Cheers,
Krisztian

Hi Krisztian,

Sorry for not replying.
I’m in the middle of a big rush atm.
I’ll have a look next week.

Cheers,

Stéphane