Fixed bug caused by multiple concurrent builds of the same resource.

Several parts of the code request resources to be loaded/built, and these separate threads were tripping over each other and causing build failures. This has been avoided by making sure the resource isn't already building before requesting it.
This commit is contained in:
CalDescent 2021-12-22 19:31:44 +00:00
parent 19173321ea
commit 361dc79ede
4 changed files with 39 additions and 13 deletions

View File

@ -56,7 +56,9 @@ public class GatewayResource {
if (build != null && build == true) {
ArbitraryDataReader reader = new ArbitraryDataReader(name, ArbitraryDataFile.ResourceIdType.NAME, service, null);
try {
reader.loadSynchronously(false);
if (!reader.isBuilding()) {
reader.loadSynchronously(false);
}
} catch (Exception e) {
// No need to handle exception, as it will be reflected in the status
}

View File

@ -938,17 +938,18 @@ public class ArbitraryResource {
// Loop until we have data
while (!Controller.isStopping()) {
attempts++;
try {
arbitraryDataReader.loadSynchronously(rebuild);
break;
} catch (MissingDataException e) {
if (attempts > 5) {
// Give up after 5 attempts
throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.INVALID_CRITERIA, "Data unavailable. Please try again later.");
if (!arbitraryDataReader.isBuilding()) {
try {
arbitraryDataReader.loadSynchronously(rebuild);
break;
} catch (MissingDataException e) {
if (attempts > 5) {
// Give up after 5 attempts
throw ApiExceptionFactory.INSTANCE.createCustomException(request, ApiError.INVALID_CRITERIA, "Data unavailable. Please try again later.");
}
}
Thread.sleep(3000L);
}
Thread.sleep(3000L);
}
java.nio.file.Path outputPath = arbitraryDataReader.getFilePath();
@ -986,7 +987,9 @@ public class ArbitraryResource {
if (build != null && build == true) {
ArbitraryDataReader reader = new ArbitraryDataReader(name, ArbitraryDataFile.ResourceIdType.NAME, service, null);
try {
reader.loadSynchronously(false);
if (!reader.isBuilding()) {
reader.loadSynchronously(false);
}
} catch (Exception e) {
// No need to handle exception, as it will be reflected in the status
}

View File

@ -107,6 +107,10 @@ public class ArbitraryDataReader {
return false;
}
public boolean isBuilding() {
return ArbitraryDataBuildManager.getInstance().isInBuildQueue(this.createQueueItem());
}
private ArbitraryDataBuildQueueItem createQueueItem() {
return new ArbitraryDataBuildQueueItem(this.resourceId, this.resourceIdType, this.service, this.identifier);
}

View File

@ -6,7 +6,9 @@ import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.qortal.api.HTMLParser;
import org.qortal.arbitrary.ArbitraryDataFile.*;
import org.qortal.arbitrary.exception.MissingDataException;
import org.qortal.arbitrary.misc.Service;
import org.qortal.controller.Controller;
import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
@ -72,8 +74,23 @@ public class ArbitraryDataRenderer {
return this.getLoadingResponse(service, resourceId);
}
// Otherwise, hang the request until the build completes
arbitraryDataReader.loadSynchronously(false);
// Otherwise, loop until we have data
int attempts = 0;
while (!Controller.isStopping()) {
attempts++;
if (!arbitraryDataReader.isBuilding()) {
try {
arbitraryDataReader.loadSynchronously(false);
break;
} catch (MissingDataException e) {
if (attempts > 5) {
// Give up after 5 attempts
return ArbitraryDataRenderer.getResponse(response, 404, "Data unavailable. Please try again later.");
}
}
}
Thread.sleep(3000L);
}
}
} catch (Exception e) {