Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#1395 - fix delay between the first active user(s) and the first request(s) in Karate-Gatling #1408

Merged
merged 1 commit into from
Dec 21, 2020

Conversation

theathlete3141
Copy link

Relevant Issues : #1395
Type of change: Bug fix for existing feature

Whilst running CatsSimulation in karate-gatling and using logging statements, I found that the line

ScanResult scanResult = new ClassGraph().acceptPaths("/").scan()

appears to be very slow (at least when using a high user rate e.g. ramp 100 users during 10 seconds).

This is called from:

Suite.java - Resource resource = ResourceUtils.getResource(workingDir, name)
Suite.java - karateBase = read("classpath:karate-base.js")
Runner.java - Suite suite = new Suite(builder)
KarateAction.scala - Runner.callAsync(name, tags.asJava, arg, perfHook)

To try to speed this up, we should do it once:

private static final ScanResult scanResult = new ClassGraph().acceptPaths("/").scan();

However, now PerfHookTests.java testPerfHook6 fails, but only when run collectively as the collective test suite (it does not fail when ran on it's own). It seems that sometimes scanResult.getResourcesWithPath(removePrefix(path)) returns null and leads to a NullPointerException rather than the expected "Feature not found exception".

Digging a bit further, the first three times this method is called it will always returns a non-null value (in this case an empty ResourceList), but after this it can (and does) return null. Therefore we need to add the handling:

if (rl == null) {
	rl = ResourceList.emptyList();
}

Note that rather than

private static final ScanResult scanResult = new ClassGraph().acceptPaths("/").scan();

We could instead do this lazily if preferred:

private static ScanResult scanResult;
private synchronized static ScanResult getScanResult() {
	if (scanResult == null) {
		scanResult = new ClassGraph().acceptPaths("/").scan();
	}
	return scanResult;
}

Or:

private static ScanResult scanResult;
private static final Object scanResultLock = new Object();
private static ScanResult getScanResult() {
	if (scanResult == null) {
		synchronized (scanResultLock) {
			if (scanResult == null) {
				scanResult = new ClassGraph().acceptPaths("/").scan();
			}
		}
	}
	return scanResult;
}

@ptrthomas ptrthomas merged commit b716ca0 into karatelabs:develop Dec 21, 2020
@ptrthomas
Copy link
Member

@theathlete3141 this is great stuff, I had a hunch this was causing some impact, e.g. the CPU utilization during the build and had tried a static init - but your solution sounds great. thanks for the investigation

This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants