英文:
locust mixed rest and websocket performance testing on the same locustfile
问题
我试图编写一个具有以下要求的测试:
- 测试包括两个调用,这两个调用必须按顺序执行。
- 第一个调用是一个REST调用(HTTP POST)。
- 第二个调用是一个WebSocket调用。
我如何可以在同一个Locust文件中实现这一点?这是可能的吗?
这是我的测试:
import time
import json
import logging
import re
import gevent
import websocket
from locust import User, FastHttpUser, SequentialTaskSet, task, between
headers = [
"auth: headers",
]
class MySocketUserClass(User):
# ...(你的WebSocket相关代码)...
class WebSocketCall(MySocketUserClass):
@task
def my_task(self):
self.connect("wss://example.com", header=headers)
# 示例订阅
self.send({'example': 'payload'})
# 等待附加的推送,同时偶尔发送心跳,就像真实客户端一样
self.sleep_with_heartbeat(10)
def on_message(self, message):
# TO BE IMPLEMENTED
pass
class RestCall(FastHttpUser):
# ...(你的REST调用相关代码)...
class UserBehaviour(SequentialTaskSet):
tasks = [RestCall, WebSocketCall]
但只有RestCall被执行。
英文:
I'm trying to write a test with the following requirementes:
- the test has two calls, the calls has to be exectuted in sequence
- the first call is a REST call (http post)
- the second one is a websocket call
How I can implement this in the same locustfile?
Is this possible?
This is my test:
import time
import json
import logging
import re
import gevent
import websocket
from locust import User, FastHttpUser, SequentialTaskSet, task, between
headers = [
"auth: headers",
]
class MySocketUserClass(User):
def connect(self, host: str, header=[], **kwargs):
self.ws = websocket.create_connection(host, header=header, **kwargs)
gevent.spawn(self.receive_loop)
def send(self, body, context={}):
self.environment.events.request.fire(
request_type="WSS",
name='test',
response_time=None,
response_length=len(body),
exception=None,
context={**self.context(), **context},
)
logging.debug(f"WSS: {body}")
self.ws.send(json.dumps(body))
def on_message(self, message): # override this method in your subclass for custom handling
print(message)
self.environment.events.request.fire(
request_type="WSR",
name='test',
response_time=0,
response_length=len(message),
exception=None,
context=self.context(),
)
def receive_loop(self):
while True:
message = self.ws.recv()
logging.debug(f"WSR: {message}")
self.on_message(message)
def sleep_with_heartbeat(self, seconds):
while seconds >= 0:
gevent.sleep(min(15, seconds))
seconds -= 15
self.send({})
class WebSocketCall(MySocketUserClass):
@task
def my_task(self):
self.connect("wss://example.com", header=headers)
# example of subscribe
self.send({'example': 'payload'})
# wait for additional pushes, while occasionally sending heartbeats, like a real client would
self.sleep_with_heartbeat(10)
def on_message(self, message):
# TO BE IMPLEMENTED
pass
class RestCall(FastHttpUser):
default_headers = {
"accept": "application/json",
"accept-encoding": "gzip, deflate, br",
"accept-language": "en-US,en;q=0.9,it;q=0.8",
"content-type": "application/json",
"sec-ch-ua": '"Chromium";v="110", "Not A(Brand";v="24", "Microsoft Edge";v="110"',
"sec-ch-ua-mobile": "?0",
"sec-ch-ua-platform": '"Windows"',
"sec-fetch-dest": "empty",
"sec-fetch-mode": "cors",
"sec-fetch-site": "same-origin",
"user-agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/110.0.0.0 Safari/537.36 Edg/110.0.1587.50",
"origin": "https://example.com",
"referer": "https://example.com",
}
def call_rest(self):
self.iam = 'rest'
with self.rest(
"POST",
"https://example.com",
json={
"example": "payload"
},
) as resp:
# CHECK RESPONSE
print(resp)
@task
def sent1(self):
self.call_rest()
class UserBehaviour(SequentialTaskSet):
tasks = [RestCall, WebSocketCall]
but only the RestCall is executed
答案1
得分: 0
问题可能在于你将多个Users放入了SequentialTaskSet任务中。我之前没见过有人这样做,所以我不知道行为会是什么样。我建议将你的MySocketUserClass设置为一个不继承自User的泛型类对象。你可以在初始化时传入environment,以便仍然可以触发事件。然后,不要再创建WebSocketCall作为另一个类,只需将task作为SequentialTaskSet内的函数即可。对于RestCallUser,你也可以做同样的事情。然后,创建一个FastHttpUser,将SequentialTaskSet作为其tasks。查看此Stack Overflow问题以获取示例:
https://stackoverflow.com/a/63573818/7355637
或者,你也可以不使用SequentialTaskSet,而是将sent1任务变得更通用,并在同一个任务内首先调用你的websocket my_task相关的内容。一个单一任务中可以包含多个函数调用。Locust仍然会适当地触发任何事件。
英文:
The problem may be that you're putting multiple Users in your SequentialTaskSet tasks. I haven't seen anyone do that before so I don't know what the behavior would be. I'd recommend making your MySocketUserClass a generic class object that doesn't inherit from User. You could make it take the environment on init so it could still fire events. Then instead of having WebSocketCall be yet another class, just make the task a function inside the SequentialTaskSet. You can actually do the same for RestCallUser. Then you make a FastHttpUser with the SequentialTaskSet as its tasks. See this SO question for an example:
https://stackoverflow.com/a/63573818/7355637
Alternatively, you can also just not use SequentialTaskSet and instead make the sent1 task more generic and call your websocket my_task stuff first inside the same task. A single task can include multiple function calls inside it. Locust will still fire whatever events appropriately.
答案2
得分: 0
以下是翻译好的内容:
你可以使用一个单独的 User 类来实现这个。
正如 SocketIOUser 的文档所述,它是:
一个包括 Socket.IO WebSocket 连接的用户。你可以轻松地将它用作普通 WebSocket 的模板,Socket.IO 只是我的使用案例。你可以使用多重继承将其与 HttpUser 结合起来(class MyUser(HttpUser, SocketIOUser))。
所以可以这样:
class MySocketIOUser(HttpUser, SocketIOUser):
@task
def my_task(self):
self.connect("wss://...")
self.client.post(...)
self.send("something")
有关 WebSocket 部分的更多信息,请参阅 https://github.com/SvenskaSpel/locust-plugins/blob/master/examples/socketio_ex.py。
英文:
You can use a single User class for this.
As SocketIOUser’s documentation states, it is:
> A User that includes a socket io websocket connection.
You could easily use this a template for plain WebSockets,
socket.io just happens to be my use case. You can use multiple
inheritance to combine this with an HttpUser
(class MyUser(HttpUser, SocketIOUser)
So something like:
class MySocketIOUser(HttpUser, SocketIOUser):
@task
def my_task(self):
self.connect("wss://...")
self.client.post(...)
self.send("something")
See https://github.com/SvenskaSpel/locust-plugins/blob/master/examples/socketio_ex.py for more about the WebSocket-parts.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。


评论