You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Gatling的exec操作按顺序执行?

问题:Gatling脚本执行顺序异常,部分操作随机跳过

我用Java编写了如下Gatling脚本(Scala下表现一致):

scenario("testScenario")
    .exec(Actions.characters)
    .exec(characterById)
    .exec(image)
    .exec(location)
    .exec(random)
    .exec(getResidents)
    .foreach("#{residents}", "resident")
    .on(Actions.getEachResident);

Actions类代码如下:

static class Actions {
    static ChainBuilder characters = exec(
            http("character")
                    .get("/character?page=2")
                    .check(jsonPath("$.results[?(@.name=='" + NAME + "')].id").saveAs("id")));

    static ChainBuilder characterById = exec(http("characterById")
            .get("/character/#{id}")
            .check(jsonPath("$.location.url").saveAs("location"))
            .check(jsonPath("$.image").saveAs("image")));

    static ChainBuilder image = exec(http("image")
            .get("#{image}"));

    static ChainBuilder location = exec(http("location")
            .get("#{location}")
            .check(jsonPath("$.residents[*]").findAll().saveAs("res"))
            .check(jsonPath("$.residents[*]").findRandom().saveAs("randomResident")));

    static ChainBuilder random = exec(http("random")
            .get("#{randomResident}"));

    static ChainBuilder getResidents = exec(session -> {
        List<String> residents = session.getList("res");
        return session.set("residents", residents);
    });

    static final ChainBuilder getEachResident =
            exec(http("Each resident").get("#{resident}"));
}

调试发现residents列表包含3个元素:

"https://rickandmortyapi.com/api/character/23"
"https://rickandmortyapi.com/api/character/204"
"https://rickandmortyapi.com/api/character/320"

多次运行脚本结果不一致:有时跳过random操作,仅执行2次resident请求;有时执行random操作,但仅执行1次resident请求。我怀疑Gatling未按顺序执行最后两个exec操作,但exec链本应是顺序执行的。请问我哪里出错了?如何让Gatling的exec操作按顺序执行?


问题原因与解决方案

核心问题

Gatling的foreach是独立的结构,你当前的写法把它和前面的exec链平级了,导致执行引擎调度时出现不确定性,进而引发操作跳过、循环次数异常等问题。

修复方法

需要明确foreach是前面所有exec步骤的后续逻辑,有两种实现方式:

方式1:用then()明确链式调用关系

修改脚本最后部分,通过then()把foreach绑定为前面步骤的后续:

scenario("testScenario")
    .exec(Actions.characters)
    .exec(characterById)
    .exec(image)
    .exec(location)
    .exec(random)
    .exec(getResidents)
    .then(
        foreach("#{residents}", "resident")
            .on(Actions.getEachResident)
    );

方式2:将foreach包裹在exec中

把foreach作为一个独立的执行步骤嵌入链中:

scenario("testScenario")
    .exec(Actions.characters)
    .exec(characterById)
    .exec(image)
    .exec(location)
    .exec(random)
    .exec(getResidents)
    .exec(
        foreach("#{residents}", "resident")
            .on(Actions.getEachResident)
    );

额外优化:简化冗余步骤

你当前的getResidents只是把res变量重命名为residents,完全可以在location步骤中直接存储目标变量,省去多余的Session操作:

static ChainBuilder location = exec(http("location")
        .get("#{location}")
        .check(jsonPath("$.residents[*]").findAll().saveAs("residents")) // 直接存为residents
        .check(jsonPath("$.residents[*]").findRandom().saveAs("randomResident")));

修改后可以直接删除exec(getResidents)步骤,脚本更简洁,也减少了出错概率。


内容的提问来源于stack exchange,提问作者Debugger

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.18 08:47:41