io.github.sinri.keel.maids.gatling.KeelGatling Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of Keel Show documentation
Show all versions of Keel Show documentation
A website framework with VERT.X for ex-PHP-ers, exactly Ark Framework Users.
The newest version!
package io.github.sinri.keel.maids.gatling;
import io.github.sinri.keel.facade.async.KeelAsyncKit;
import io.github.sinri.keel.logger.event.KeelEventLogger;
import io.github.sinri.keel.verticles.KeelVerticleImplWithEventLogger;
import io.vertx.core.*;
import io.vertx.core.shareddata.Counter;
import java.util.Random;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.function.Supplier;
import static io.github.sinri.keel.facade.KeelInstance.Keel;
/**
* Gatling Gun with multi barrels, for parallel tasks in clustered vertx runtime.
*
* @since 2.9.1
* @since 2.9.3 change to VERTICLE
*/
public class KeelGatling extends KeelVerticleImplWithEventLogger {
private final Options options;
private final AtomicInteger barrelUsed = new AtomicInteger(0);
private KeelGatling(Options options) {
this.options = options;
}
public static Future deploy(String gatlingName, Handler optionHandler) {
Options options = new Options(gatlingName);
optionHandler.handle(options);
KeelGatling keelGatling = new KeelGatling(options);
return Keel.getVertx().deployVerticle(keelGatling, new DeploymentOptions().setThreadingModel(ThreadingModel.WORKER));
}
protected Future rest() {
int actualRestInterval = new Random().nextInt(
Math.toIntExact(options.getAverageRestInterval() / 2)
) + options.getAverageRestInterval();
return KeelAsyncKit.sleep(actualRestInterval);
}
@Override
protected void startAsKeelVerticle(Promise startPromise) {
barrelUsed.set(0);
KeelAsyncKit.repeatedlyCall(routineResult -> {
return fireOnce();
})
.andThen(ar -> {
super.startAsKeelVerticle(startPromise);
});
}
private Future fireOnce() {
if (barrelUsed.get() >= options.getBarrels()) {
getLogger().debug(r -> r.message("BARREL FULL"));
return rest();
}
return Future.succeededFuture()
.compose(v -> loadOneBullet())
.compose(bullet -> {
if (bullet == null) {
return rest();
}
barrelUsed.incrementAndGet();
fireBullet(bullet, firedAR -> {
if (firedAR.failed()) {
getLogger().exception(firedAR.cause(), r -> r.message("BULLET FIRED ERROR"));
} else {
getLogger().info(r -> r.message("BULLET FIRED DONE"));
}
barrelUsed.decrementAndGet();
});
return KeelAsyncKit.sleep(10L);
})
.recover(throwable -> {
getLogger().exception(throwable, r -> r.message("FAILED TO LOAD BULLET"));
return rest();
});
}
/**
* Seek one bullet from anywhere with a certain rule.
*
* @return Future of a runnable bullet, or null.
*/
private Future loadOneBullet() {
return Keel.getVertx().sharedData()
.getLock("KeelGatling-" + this.options.getGatlingName() + "-Load")
.compose(lock -> this.options.getBulletLoader().get().andThen(ar -> lock.release()));
}
protected Future requireExclusiveLocksOfBullet(Bullet bullet) {
if (bullet.exclusiveLockSet() != null && !bullet.exclusiveLockSet().isEmpty()) {
AtomicBoolean blocked = new AtomicBoolean(false);
return KeelAsyncKit.iterativelyCall(
bullet.exclusiveLockSet(),
exclusiveLock -> {
String exclusiveLockName = "KeelGatling-Bullet-Exclusive-Lock-" + exclusiveLock;
return Keel.getVertx().sharedData()
.getCounter(exclusiveLockName)
.compose(Counter::incrementAndGet)
.compose(increased -> {
if (increased > 1) {
blocked.set(true);
}
return Future.succeededFuture();
});
})
.compose(v -> {
if (blocked.get()) {
return releaseExclusiveLocksOfBullet(bullet)
.eventually(() -> Future.failedFuture(new Exception("This bullet met Exclusive Lock Block.")));
}
return Future.succeededFuture();
});
} else {
return Future.succeededFuture();
}
}
protected Future releaseExclusiveLocksOfBullet(Bullet bullet) {
if (bullet.exclusiveLockSet() != null && !bullet.exclusiveLockSet().isEmpty()) {
return KeelAsyncKit.iterativelyCall(bullet.exclusiveLockSet(), exclusiveLock -> {
String exclusiveLockName = "KeelGatling-Bullet-Exclusive-Lock-" + exclusiveLock;
return Keel.getVertx().sharedData().getCounter(exclusiveLockName)
.compose(counter -> counter.decrementAndGet()
.compose(x -> Future.succeededFuture()));
});
} else {
return Future.succeededFuture();
}
}
private void fireBullet(Bullet bullet, Handler> handler) {
Promise promise = Promise.promise();
Future.succeededFuture()
.compose(v -> requireExclusiveLocksOfBullet(bullet)
.compose(locked -> bullet.fire()
.andThen(fired -> releaseExclusiveLocksOfBullet(bullet)))
)
.andThen(firedAR -> bullet.ejectShell(firedAR)
.onComplete(ejected -> {
if (firedAR.failed()) {
promise.fail(firedAR.cause());
} else {
promise.complete();
}
})
);
promise.future().andThen(handler);
}
@Override
protected KeelEventLogger buildEventLogger() {
return null;
}
public static class Options {
private final String gatlingName;
private int barrels;
private int averageRestInterval;
private Supplier> bulletLoader;
// private KeelEventLogger logger;
public Options(String gatlingName) {
this.gatlingName = gatlingName;
this.barrels = 1;
this.averageRestInterval = 1000;
this.bulletLoader = () -> Future.succeededFuture(null);
// this.logger = KeelEventLogger.silentLogger();
}
/**
* @return 加特林机枪名称(集群中各节点之间的识别同一组加特林机枪类的实例用)
*/
public String getGatlingName() {
return gatlingName;
}
/**
* @return 枪管数量(并发任务数)
*/
public int getBarrels() {
return barrels;
}
/**
* @param barrels 枪管数量(并发任务数)
*/
public Options setBarrels(int barrels) {
this.barrels = barrels;
return this;
}
/**
* @return 弹带更换平均等待时长(没有新任务时的休眠期,单位0.001秒)
*/
public int getAverageRestInterval() {
return averageRestInterval;
}
/**
* @param averageRestInterval 弹带更换平均等待时长(没有新任务时的休眠期,单位0.001秒)
*/
public Options setAverageRestInterval(int averageRestInterval) {
this.averageRestInterval = averageRestInterval;
return this;
}
/**
* @return 供弹器(新任务生成器)
*/
public Supplier> getBulletLoader() {
return bulletLoader;
}
/**
* @param bulletLoader 供弹器(新任务生成器)
*/
public Options setBulletLoader(Supplier> bulletLoader) {
this.bulletLoader = bulletLoader;
return this;
}
// /**
// * @return 日志记录仪
// */
// public KeelEventLogger getLogger() {
// return logger;
// }
//
// /**
// * @param logger 日志记录仪
// */
// public Options setLogger(KeelEventLogger logger) {
// this.logger = logger;
// return this;
// }
}
}
© 2015 - 2024 Weber Informatics LLC | Privacy Policy