Skip to content
Merged
Show file tree
Hide file tree
Changes from 29 commits
Commits
Show all changes
31 commits
Select commit Hold shift + click to select a range
d7b9161
Kanban 2207: Release AsyncQueryRequest connections through the lendin…
cnathe Oct 13, 2026
39c8a95
Kanban 2207: Cancel abandoned requests' statements in the database, w…
cnathe Oct 13, 2026
a064720
Kanban 2207: Exempt exports from the read-only request timeout
cnathe Oct 13, 2026
ec56498
Return an error for timed-out requests and count shutdown cancels
cnathe Oct 13, 2026
b99faf7
Merge remote-tracking branch 'origin/develop' into fb_request_kill_2207
cnathe Oct 13, 2026
bb48cc1
isServerCancelledQuery fix
cnathe Oct 13, 2026
e56a94f
Add tests for cancel bookkeeping, the timeout sweep, and cancelled-qu…
cnathe Oct 13, 2026
d62f796
Fix cancel races and wrapped cancelled-query detection
cnathe Oct 13, 2026
e91b066
Add tests for cancel bookkeeping, the timeout sweep, and cancelled-qu…
cnathe Oct 13, 2026
1f08889
Keep a request's cancel state on its RequestTracker
cnathe Oct 13, 2026
b107e2d
drop the PostgreSQL Assume from the new tests.
cnathe Oct 14, 2026
f8bec6f
Use an unpooled connection for the pg_cancel_backend fallback
cnathe Oct 14, 2026
4c78473
Bound the driver cancel's timeout and detect wrapped timed-out aborts
cnathe Oct 14, 2026
f3ebaa2
Log one INFO line per cancelled request and move the step lines to DEBUG
cnathe Oct 14, 2026
a33e8f8
Log an untracked interrupt at INFO and name the exit line's spids as …
cnathe Oct 14, 2026
f36f9ab
Merge remote-tracking branch 'origin/develop' into fb_request_kill_2207
cnathe Oct 14, 2026
b9bef46
Merge remote-tracking branch 'origin/develop' into fb_request_kill_2207
cnathe Oct 15, 2026
1762bdc
Merge remote-tracking branch 'origin/develop' into fb_request_kill_2207
cnathe Oct 16, 2026
5e3be7c
Merge remote-tracking branch 'origin/develop' into fb_request_kill_2207
cnathe Oct 17, 2026
6342a2b
Merge remote-tracking branch 'origin/develop' into fb_request_kill_2207
cnathe Oct 19, 2026
0c668d2
Code review feedback part 1: Rename cancel methods, move cancelSignal…
cnathe Oct 19, 2026
bfc3d44
Code review feedback part 2: Run the cancel fallback before release a…
cnathe Oct 19, 2026
d372239
Code review feedback part 2: Return a 503 from API actions for timed-…
cnathe Oct 19, 2026
cf105fa
Code review feedback part 3: Detach the request thread's connection h…
cnathe Oct 19, 2026
627e150
Code review feedback part 4: Cancel queries at shutdownStarted, just …
cnathe Oct 19, 2026
abcd2ca
Discard connections whose async statement was cancelled
cnathe Oct 19, 2026
b829b3c
Discard a stuck async worker's connection and share the backend check…
cnathe Oct 19, 2026
e412a6f
Cancel non-Postgres queries on timeout and fix review findings
cnathe Oct 19, 2026
77baa1c
Merge remote-tracking branch 'origin/develop' into fb_request_kill_2207
cnathe Oct 20, 2026
1166e96
Merge remote-tracking branch 'origin/develop' into fb_request_kill_2207
cnathe Oct 21, 2026
f972600
Route pipeline cancels through RequestCancellation and connect outsid…
cnathe Oct 21, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions api/src/org/labkey/api/ApiModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@
import org.labkey.api.data.AbstractForeignKey;
import org.labkey.api.data.AccumulatingCommitTask;
import org.labkey.api.data.Aggregate;
import org.labkey.api.data.AsyncQueryRequest;
import org.labkey.api.data.AtomicDatabaseInteger;
import org.labkey.api.data.BindingTestCase;
import org.labkey.api.data.BooleanFormat;
Expand All @@ -78,6 +79,7 @@
import org.labkey.api.data.NameGenerator;
import org.labkey.api.data.PropertyManager;
import org.labkey.api.data.RecordFactory;
import org.labkey.api.data.RequestCancellation;
import org.labkey.api.data.RepeatedCommitTaskMonitor;
import org.labkey.api.data.ResultSetSelectorTestCase;
import org.labkey.api.data.RowTrackingResultSetWrapper;
Expand All @@ -92,6 +94,7 @@
import org.labkey.api.data.Table;
import org.labkey.api.data.TableSelectorTestCase;
import org.labkey.api.data.TempTableInClauseGenerator;
import org.labkey.api.data.TransactionFilter;
import org.labkey.api.data.WorkbookContainerType;
import org.labkey.api.data.dialect.JdbcMetaDataTest;
import org.labkey.api.data.dialect.ParameterSubstitutionTest;
Expand Down Expand Up @@ -528,6 +531,7 @@ public void registerServlets(ServletContext servletCtx)
ApiKeyManager.TestCase.class,
ApiQueryResponse.TestCase.class,
AppPropsTestCase.class,
AsyncQueryRequest.TestCase.class,
AtomicDatabaseInteger.TestCase.class,
BindingTestCase.class,
BlockingCache.BlockingCacheTest.class,
Expand Down Expand Up @@ -573,6 +577,7 @@ public void registerServlets(ServletContext servletCtx)
QueryDataIteratorBuilder.TestCase.class,
QueryView.TestCase.class,
RecordFactory.TestCase.class,
RequestCancellation.TestCase.class,
RepeatedCommitTaskMonitor.IntegrationTestCase.class,
ResultSetDataIterator.TestCase.class,
ResultSetSelectorTestCase.class,
Expand All @@ -592,6 +597,7 @@ public void registerServlets(ServletContext servletCtx)
Table.TestCase.class,
TableSelectorTestCase.CoreTableSelectorTest.class,
TempTableInClauseGenerator.TestCase.class,
TransactionFilter.TestCase.class,
URLHelper.TestCase.class,
UserKeySimpleCache.TestCase.class,
UserManager.TestCase.class,
Expand Down
6 changes: 5 additions & 1 deletion api/src/org/labkey/api/action/ApiResponseWriter.java
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,9 @@ public int getErrorResponseStatus(Throwable ex)
if (ex instanceof HttpStatusException statusEx)
return statusEx.getStatus();

if (ExceptionUtil.isRequestTimeout(ex))
return HttpServletResponse.SC_SERVICE_UNAVAILABLE;

if (ex instanceof BatchValidationException || ex instanceof ValidationException)
return defaultErrorStatus;

Expand Down Expand Up @@ -262,12 +265,13 @@ public final void writeResponse(Object obj) throws IOException
public void writeResponse(Throwable e) throws IOException
{
int status = getErrorResponseStatus(e);
boolean timedOut = ExceptionUtil.isRequestTimeout(e);
e = ExceptionUtil.unwrapException(e);

try
{
setResponseStatus(status);
var json = toJSON(e);
var json = timedOut ? new JSONObject().put("exception", ExceptionUtil.REQUEST_TIMEOUT_MESSAGE) : toJSON(e);
json.put("success", false);
writeObject(json);
}
Expand Down
7 changes: 6 additions & 1 deletion api/src/org/labkey/api/action/SpringActionController.java
Original file line number Diff line number Diff line change
Expand Up @@ -569,6 +569,7 @@ public ModelAndView handleRequest(HttpServletRequest request, @NotNull HttpServl

checkable.checkPermissions();

boolean export = ExportAction.class.isAssignableFrom(actionClass);
// Actions can annotate themselves with an ActionType, which helps custom schemas that want to limit access from generic actions
if (actionClass.isAnnotationPresent(Action.class))
{
Expand All @@ -578,12 +579,16 @@ public ModelAndView handleRequest(HttpServletRequest request, @NotNull HttpServl
actionAnnotation.value().equals(ActionType.SelectData.class) ||
actionAnnotation.value().equals(ActionType.SelectMetaData.class))
{
// Consider these action types read-only and eligible for killing after a timeout
// Consider these action types read-only and, except for exports, eligible for killing after a timeout
request.setAttribute(TransactionFilter.READ_ONLY_ATTRIBUTE_NAME, true);
}
export |= actionAnnotation.value().equals(ActionType.Export.class);
QueryService.get().setEnvironment(QueryService.Environment.ACTION, actionAnnotation.value());
}

if (export)
request.setAttribute(TransactionFilter.EXPORT_ATTRIBUTE_NAME, true);

// After the permission check so unauthorized requests can't consume @ConcurrencyLimit permits, and held
// through rendering because the action's memory is live for that whole time.
try (ConcurrencyLimiter.Permit ignored = ConcurrencyLimiter.acquire(actionClass, context))
Expand Down
Loading
Loading