0

Scenario

I am creating some records in a system using three requests of its API. In the first request I need to send and Id which for testing and tracking purposes I am using a consecutive number generated in a sampler.

I need to test how the system behaves under high loads, so I started with 16 threads per second and set the loop to 3000 to run it for about 50 minutes to monitor behavior.

I expected to run for about 50 minutes and create 48000 records.

What happened?

Once I ran it, I started watching some errors in the first request, related to IDs being duplicated. Some requests were rejected because the Id already exists. This is correct behavior, but I did not expect to be generating duplicated Ids.

How is it done? THe overall structure is this. Please consider the grayed-out items are disabled.

enter image description here

The SetUp Thread Group has a Sampler to initialize the counter of IDs. I use a file to store the last used Id, and this sampler verifies the file exists or not and creates it accordingly with an initial value.

All sampler codes are Java, BeanShell 2.0b6 and BeanShell Engine 1.0.

import java.io.*;
import java.util.concurrent.locks.ReentrantLock;

// Define the file path for the counter
File counterFile = new File("/Users/rickersilva/Documents/Zenus2Testing/prelive-counter.txt");
ReentrantLock lock = new ReentrantLock();

lock.lock();
try {
    // Check if the counter file exists
    if (!counterFile.exists()) {
        // If not, create it and set the initial value
        BufferedWriter writer = new BufferedWriter(new FileWriter(counterFile));
        writer.write("90000000"); // Initial value
        writer.close();
        log.info("DEV_LOG: Counter initialized with value 90000000");
    } else {
        log.info("DEV_LOG: Counter file already exists, skipping initialization.");
    }
} catch (IOException e) {
    log.error("DEV_LOG: Error initializing counter: " + e);
} finally {
    lock.unlock();
}

Having set that up, I set some user defined variables not related to this case, headers and so on. In the Create Person request I have the DNI increment preprocessor. Its purpose is to provide a safe way to acces the file, read the ID, increment it and save it back to the file. I use a lock to prevent the threads to open it at the same time, expecting not to use the same Id in create person requests. This is clearly not working, and here is the code.

import java.io.*;
import java.util.concurrent.locks.ReentrantLock;

ReentrantLock lock = new ReentrantLock();
File counterFile = new File("/Users/rickersilva/Documents/Zenus2Testing/prelive-counter.txt");
int currentDni;
int nextDni;
String idNumber;

lock.lock();
try {
    // Read the current value of personDni from the file
    BufferedReader reader = new BufferedReader(new FileReader(counterFile));
    currentDni = Integer.parseInt(reader.readLine().trim());
    reader.close();
    
    // Increment the personDni and update the file
    nextDni = currentDni + 1;
    BufferedWriter writer = new BufferedWriter(new FileWriter(counterFile, false));
    writer.write(Integer.toString(nextDni));
    writer.close();
    
    // Set the personDni variable in JMeter
    idNumber = "16" + Integer.toString(nextDni);
    vars.put("idNumber", idNumber);
} catch (Exception e) {
    log.error("DEV_LOG: Error processing personDni: " + e);
} finally {
    lock.unlock();
}

The extractor catches the personId returned by the API to be used in the next requests.

I cannot see why this could be failing. Highly possible my understanding of locking is not good in this scenario. But I cannot figure out other way to accomplish this. I appreciate your time and help.

2 Answers 2

1

It looks you're trying to implement Critical Section Controller, check out its source code to see how it should be done.

I don't think you're going into right direction because in your case you won't have concurrency more than 1 virtual user executing this block. So it would make much more sense to go for JMeter's build-in Counter configuration element

Also I would recommend reconsider using Beanshell, since JMeter 3.1 you should be using JSR223 Test Elements and Groovy language for scripting.

Sign up to request clarification or add additional context in comments.

2 Comments

I will check what you say. Maybe I forgot to say that I was running 16 concurrent threads per second. Related to groovy, I run into a lot of problems using groovy in my system, it did not even run. Then I realized it is one of those things that require you to downgrade your java versions or have multiple versions installed and that is just too much unnecessary complexity for me.
JMeter build in counter worked for me and simplify a lot my test structure. Thank you.
0

This answer is a more detailed one based on the suggestion of Ian G above to use the Jmeter built-in counter.

  1. Add a Loop Controller in your Test Plan, and move all your HTTP Requests and other items related to the execution of the test into it.

Menu sequence is as follows: From the left test plan tree, right click on Thread Group -> Add -> Logic Controller -> Loop Controller

  1. Inside The loop Counter, and in the order you need, add a Counter.

Menu sequence is as follows: From the left panel tree, right click on Loop Controller -> Add -> Config element -> Counter

  1. And configure it. set a Starting value, the increment and the variable name, which you could use in the request's bodies. Setting those attributes could be enough. The final appearance of my test plan is as follows.

This picture just shows hoe my test plan is organized. The relevant part is that below Thread Grou, there is a Loop Controller, inside this, is a Counter at the beginning, before the requests.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.