Simulating Delayed Order Cancellation with Java DelayQueue for Performance Testing
This article explains how to meet a performance‑testing requirement for cancelling orders 10 seconds after placement by leveraging Java's thread‑safe DelayQueue, detailing the design, implementation, test case, execution steps, and observed results.
The author initially believed their performance‑testing scenarios were complete, but a new requirement to cancel orders 10 seconds after placement revealed a gap.
Requirement
In a specific test, orders are placed and, if successful, must be cancelled after a configurable delay to avoid exhausting test user assets. The development team observed that a short interval between order and cancellation caused issues, prompting the need for delayed cancellation.
Approach
The solution uses java.util.concurrent.DelayQueue, a thread‑safe queue designed for delayed processing. An alternative java.util.Timer was considered but rejected because it creates extra threads and makes rate control harder.
Implementation
A custom class FunDelay implements java.util.concurrent.Delayed to store the order ID and the target execution time. The class provides getDelay and compareTo methods required by the interface.
private static class FunDelay implements Delayed {
int time;
String id;
FunDelay(String id) {
this.time = getMark() + delay;
this.id = id;
}
@Override
public long getDelay(TimeUnit unit) {
return time - getMark();
}
@Override
public int compareTo(Delayed o) {
FunDelay item = (FunDelay) o;
return this.time < item.time ? -1 : 1;
}
}Test Case
The existing test framework is extended by overriding the after method to handle any remaining order IDs in the delay queue after the test ends. The core tester class FunTester maintains a DelayQueue<FunDelay> and processes due orders in its doing method.
private static class FunTester extends FixedThread<Trade> {
DelayQueue<FunDelay> ids = new DelayQueue<>();
FunTester(Trade o, int limit) { super(o, limit, true); }
@Override
protected void doing() throws Exception {
def res = f.order(********);
if (0 == res.getInteger("code")) {
def array = res.getJSONArray("data").get(0);
def id = array.getString("Id");
ids.add(new FunDelay(id));
} else {
output(res.toString());
}
int i = 0;
while (true) {
if (i++ > 10) break;
def poll = ids.poll();
if (poll == null) break;
f.stop("***", poll.id);
}
}
@Override
protected void after() {
super.after();
sleep(1.0);
f.clearGrid();
}
@Override
ThreadBase clone() { return new FunTester(f, limit); }
}Execution
The main method adds a fourth command‑line argument to parameterize the delay time. It initializes the client, parses arguments, creates multiple FunTester tasks, and starts them with a descriptive label.
static int delay;
public static void main(String[] args) {
ClientManage.init(10, 5, 0, "", 0);
ArgsUtil util = new ArgsUtil(args);
int thread = util.getIntOrdefault(0, 1);
int times = util.getIntOrdefault(1, 1000);
int runuptime = util.getIntOrdefault(2, 0);
delay = util.getIntOrdefault(3, 3);
Constant.RUNUP_TIME = runuptime;
Common.PRINT_RESPONSE = false;
Common.VERIFY = false;
FunLibrary.LOG_KEY = false;
Common.MOCO = true;
Common.setHost();
def line = DataUtils.getMocoTokens();
def tasks = [];
thread.times {
def base = getBase(line.get(getRandomInt(500)));
def drive = new Trade(base);
tasks << new FunTester(drive, times);
}
new Concurrent(tasks, "下单和延迟10s撤单").start();
over();
}Test Result
Using the default 3‑second delay, the log screenshot shows orders starting at 17 s and cancellations beginning at 20 s, confirming that the delayed‑cancellation requirement is satisfied.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
