artilleryio / artillery-core

artillery-core - deprecated
Mozilla Public License 2.0
29 stars 105 forks source link

Data got emit twice in socket.io engine #223

Open NHP95 opened 6 years ago

NHP95 commented 6 years ago

I had a json test script looked like this :

{
  "config": {
    "target": "ws://192.168.74.17:8000",
    "phases": [
      {
        "duration": 1,
        "arrivalRate": 1
      }
    ],
    "processor": "./laura_processor.js",
    "variables": {
      "channelId": "1f49b260-94eb-41e2-8f9f-fca20ba9fc96",
      "channelToken": "ad09a6b1-19ea-47a1-9b8d-b2c0f42f0a98",
      "recipientId": "ad09a6b1-19ea-47a1-9b8d-b2c0f42f0a98",
      "chatId": "1f49b260-94eb-41e2-8f9f-fca20ba9fc96-{{senderId}}",
      "senderId": ""
    },
    "socketio": {
      "transports": [
        "websocket"
      ]
    }
  },
  "scenarios": [
    {
      "engine": "socketio",
      "flow": [
        {
          "emit": {
            "channel": "message",
            "data": {
              "action": "UNK",
              "dataType": "TEXT",
              "data": "Hello",
              "conversationInfo": {
                "channelId": "{{channelId}}",
                "channelToken": "{{channelToken}}",
                "recipientId": "{{recipientId}}",
                "chatId": "1f49b260-94eb-41e2-8f9f-fca20ba9fc96-b0528b2f-fbb2-4772-ae08-111c1cab15bc",
                "senderId": "b0528b2f-fbb2-4772-ae08-111c1cab15bc"
              }
            },
            "response": {
              "channel": "message",
              "capture": {
                "json": "$.data",
                "as": "answer"
              }
            }
          }
        }
      ]
    }
  ]
}

As long as the "response" node shows up in the test script, data will be emitted twice. If I remove the "response" node, everything works fine. I'm not sure if anyone has faced the same issue. The number of requests in this example was also doubled when I added response node under "add user" channel to capture response body.

minhhoangvn commented 6 years ago

I got the same issue and i am very appreciate if anyone knows how to work around it.

NHP95 commented 6 years ago

For anyone who got into the same issue, I kinda found a way to work around this problem by making use of JavaScript.

{
  "config": {
    "target": "http://localhost:8000",
    "phases": [
      {
        "duration": 1,
        "arrivalRate": 1
      }
    ],
    "processor": "./custom_processor_metric.js",
    "variables": {
      "channelId": "1f49b260-94eb-41e2-8f9f-fca20ba9fc96",
      "channelToken": "ad09a6b1-19ea-47a1-9b8d-b2c0f42f0a98",
      "recipientId": "ad09a6b1-19ea-47a1-9b8d-b2c0f42f0a98",
      "senderId": ""
    },
    "socketio": {
      "transports": [
        "websocket"
      ]
    }
  },
  "scenarios": [
    {
      "name": "Scenario 1",
      "engine": "socketio",
      "flow": [
        {
          "function": "initConversation"
        },
        {
          "function": "sendMessage"
        },
        {
          "function": "sendMessage"
        },
        {
          "function": "sendMessage"
        }
      ]
    },
    {
      "name": "Scenario 2",
      "engine": "socketio",
      "flow": [
        {
          "function": "initConversation"
        },
        {
          "function": "sendMessage"
        }
      ]
    }
  ]
}

Given the script above, I used JS function instead of directly emitting the message to serve. With this approach, you have to manually verify the response yourself.

module.exports = {
    initConversation: initConversation,
    sendMessage: sendMessage
};

const artillery = require('artillery-core');

function initConversation(context, events, done) {
    events.emit("request");
    let startedAt = process.hrtime();
    context.sockets["/"].emit("message",
        {
            "action": "START_NEW_CONVERSATION", "dataType": "UNK", "data": {}, "conversationInfo": { "channelId": context.vars.channelId, "channelToken": context.vars.channelToken, "recipientId": context.vars.recipientId, "chatId": null, "senderId": null }
        });
    return processSender(context, events, done, startedAt);
}

function processSender(context, events, done, startedAt) {
    context.sockets["/"].on("message", function (res) {
        try {
            context.vars.senderId = res.conversationInfo.senderId;
        } catch (error) { // do something
        }

        if (context.vars.senderId) {
            markEndTime(events, context, startedAt);
            context.sockets["/"].off("message");
            return done();
        }
    });
}

function sendMessage(context, events, done) {
    events.emit("request");
    const startedAt = process.hrtime();
    context.sockets["/"].emit("message",
        {
            "action": "UNK", "dataType": "TEXT", "data": "Hello from JS", "conversationInfo": { "channelId": context.vars.channelId, "channelToken": context.vars.channelToken, "recipientId": context.vars.recipientId, "chatId": context.vars.channelId + '-' + context.vars.senderId, "senderId": context.vars.senderId }
        });
    return waitForResponse(context, events, done, startedAt, startTime);
}

function waitForResponse(context, events, done, startedAt, startTime) {
    context.sockets["/"].on("message", function (res) {
        if (res.action == "UNK") {
            markEndTime(events, context, startedAt);
            context.sockets["/"].off("message");
            return done();        
        }
    });
}

function markEndTime(ee, context, startedAt) {
    let endedAt = process.hrtime(startedAt);
    let delta = (endedAt[0] * 1e9) + endedAt[1];
    ee.emit('response', delta, 0, context._uid);
}