Skip to content

Commit f811f7e

Browse files
committed
Add session property for passing query client timeout value (#25210)
Summary: Currently, client timeout value is passed via query.client.timeout config property which applies to all queries. Adding corresponding session property which can be used to specify timeout values at query level, if needed. Differential Revision: D75480566
1 parent 3ef7769 commit f811f7e

File tree

5 files changed

+67
-6
lines changed

5 files changed

+67
-6
lines changed

presto-docs/src/main/sphinx/admin/properties-session.rst

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -406,3 +406,16 @@ Setting a duration controls how long to cache data.
406406

407407
The value represents the max background fetch threads for refreshing metadata.
408408

409+
Query Manager Properties
410+
------------------------
411+
412+
``query_client_timeout``
413+
^^^^^^^^^^^^^^^^^^^^^^^^
414+
415+
* **Type:** ``Duration``
416+
* **Default value:** ``5m``
417+
418+
This property can be used to configure how long a query runs without contact
419+
from the client application, such as the CLI, before it's abandoned.
420+
421+
The corresponding configuration property is :ref:`admin/properties:\`\`query.client.timeout\`\``.

presto-docs/src/main/sphinx/admin/properties.rst

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1090,4 +1090,16 @@ system will keep logs for the past 15 days.
10901090
* **Type:** ``data size``
10911091
* **Default value:** ``100MB``
10921092

1093-
The maximum file size for the log file of the HTTP server.
1093+
The maximum file size for the log file of the HTTP server.
1094+
1095+
Query Manager Properties
1096+
------------------------
1097+
1098+
``query.client.timeout``
1099+
^^^^^^^^^^^^^^^^^^^^^^^^
1100+
1101+
* **Type:** ``Duration``
1102+
* **Default value:** ``5m``
1103+
1104+
This property can be used to configure how long a query runs without contact
1105+
from the client application, such as the CLI, before it's abandoned.

presto-main-base/src/main/java/com/facebook/presto/SystemSessionProperties.java

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,7 @@ public final class SystemSessionProperties
330330
public static final String SINGLE_NODE_EXECUTION_ENABLED = "single_node_execution_enabled";
331331
public static final String EXPRESSION_OPTIMIZER_NAME = "expression_optimizer_name";
332332
public static final String ADD_EXCHANGE_BELOW_PARTIAL_AGGREGATION_OVER_GROUP_ID = "add_exchange_below_partial_aggregation_over_group_id";
333+
public static final String QUERY_CLIENT_TIMEOUT = "query_client_timeout";
333334

334335
// TODO: Native execution related session properties that are temporarily put here. They will be relocated in the future.
335336
public static final String NATIVE_AGGREGATION_SPILL_ALL = "native_aggregation_spill_all";
@@ -1890,7 +1891,16 @@ public SystemSessionProperties(
18901891
booleanProperty(ADD_EXCHANGE_BELOW_PARTIAL_AGGREGATION_OVER_GROUP_ID,
18911892
"Enable adding an exchange below partial aggregation over a GroupId node to improve partial aggregation performance",
18921893
featuresConfig.getAddExchangeBelowPartialAggregationOverGroupId(),
1893-
false));
1894+
false),
1895+
new PropertyMetadata<>(
1896+
QUERY_CLIENT_TIMEOUT,
1897+
"Configures how long the query runs without contact from the client application, such as the CLI, before it's abandoned",
1898+
VARCHAR,
1899+
Duration.class,
1900+
queryManagerConfig.getClientTimeout(),
1901+
false,
1902+
value -> Duration.valueOf((String) value),
1903+
Duration::toString));
18941904
}
18951905

18961906
public static boolean isSpoolingOutputBufferEnabled(Session session)
@@ -3221,4 +3231,9 @@ public static boolean isCanonicalizedJsonExtract(Session session)
32213231
{
32223232
return session.getSystemProperty(CANONICALIZED_JSON_EXTRACT, Boolean.class);
32233233
}
3234+
3235+
public static Duration getQueryClientTimeout(Session session)
3236+
{
3237+
return session.getSystemProperty(QUERY_CLIENT_TIMEOUT, Duration.class);
3238+
}
32243239
}

presto-main-base/src/main/java/com/facebook/presto/execution/QueryTracker.java

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
import java.util.concurrent.atomic.AtomicInteger;
4242
import java.util.concurrent.atomic.AtomicLong;
4343

44+
import static com.facebook.presto.SystemSessionProperties.getQueryClientTimeout;
4445
import static com.facebook.presto.SystemSessionProperties.getQueryMaxExecutionTime;
4546
import static com.facebook.presto.SystemSessionProperties.getQueryMaxRunTime;
4647
import static com.facebook.presto.execution.QueryLimit.Source.QUERY;
@@ -74,8 +75,6 @@ public class QueryTracker<T extends TrackedQuery>
7475
private final ConcurrentMap<QueryId, T> queries = new ConcurrentHashMap<>();
7576
private final Queue<T> expirationQueue = new LinkedBlockingQueue<>();
7677

77-
private final Duration clientTimeout;
78-
7978
private final ScheduledExecutorService queryManagementExecutor;
8079

8180
@GuardedBy("this")
@@ -88,7 +87,6 @@ public QueryTracker(QueryManagerConfig queryManagerConfig, ScheduledExecutorServ
8887
requireNonNull(queryManagerConfig, "queryManagerConfig is null");
8988
this.minQueryExpireAge = queryManagerConfig.getMinQueryExpireAge();
9089
this.maxQueryHistory = queryManagerConfig.getMaxQueryHistory();
91-
this.clientTimeout = queryManagerConfig.getClientTimeout();
9290
this.maxTotalRunningTaskCountToKillQuery = queryManagerConfig.getMaxTotalRunningTaskCountToKillQuery();
9391
this.maxQueryRunningTaskCount = queryManagerConfig.getMaxQueryRunningTaskCount();
9492

@@ -384,7 +382,8 @@ private void failAbandonedQueries()
384382

385383
private boolean isAbandoned(T query)
386384
{
387-
long oldestAllowedHeartbeatInMillis = currentTimeMillis() - clientTimeout.toMillis();
385+
Duration queryClientTimeout = getQueryClientTimeout(query.getSession());
386+
long oldestAllowedHeartbeatInMillis = currentTimeMillis() - queryClientTimeout.toMillis();
388387
long lastHeartbeat = query.getLastHeartbeatInMillis();
389388

390389
return lastHeartbeat > 0 && lastHeartbeat < oldestAllowedHeartbeatInMillis;

presto-tests/src/test/java/com/facebook/presto/tests/TestQueryManager.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414
package com.facebook.presto.tests;
1515

1616
import com.facebook.presto.Session;
17+
import com.facebook.presto.SystemSessionProperties;
1718
import com.facebook.presto.common.RuntimeStats;
1819
import com.facebook.presto.cost.StatsAndCosts;
1920
import com.facebook.presto.dispatcher.DispatchManager;
@@ -63,6 +64,7 @@
6364
import static com.facebook.presto.execution.TestQueryRunnerUtil.waitForQueryState;
6465
import static com.facebook.presto.execution.resourceGroups.db.H2TestUtil.getSimpleQueryRunner;
6566
import static com.facebook.presto.operator.BlockedReason.WAITING_FOR_MEMORY;
67+
import static com.facebook.presto.spi.StandardErrorCode.ABANDONED_QUERY;
6668
import static com.facebook.presto.spi.StandardErrorCode.EXCEEDED_CPU_LIMIT;
6769
import static com.facebook.presto.spi.StandardErrorCode.EXCEEDED_GLOBAL_MEMORY_LIMIT;
6870
import static com.facebook.presto.spi.StandardErrorCode.EXCEEDED_OUTPUT_POSITIONS_LIMIT;
@@ -273,6 +275,26 @@ public void testQueryOutputSizeExceeded()
273275
}
274276
}
275277

278+
@Test(timeOut = 60_000L)
279+
public void testQueryClientTimeoutExceeded()
280+
throws Exception
281+
{
282+
Session session = Session.builder(TEST_SESSION)
283+
.setSystemProperty(SystemSessionProperties.QUERY_CLIENT_TIMEOUT, "1s")
284+
.build();
285+
286+
try (DistributedQueryRunner queryRunner = builder().setSingleExtraProperty("query.client.timeout", "3m").build()) {
287+
QueryId queryId = createQuery(queryRunner, session, "SELECT COUNT(*) FROM lineitem");
288+
waitForQueryState(queryRunner, queryId, FAILED);
289+
QueryManager queryManager = queryRunner.getCoordinator().getQueryManager();
290+
BasicQueryInfo queryInfo = queryManager.getQueryInfo(queryId);
291+
assertEquals(queryInfo.getState(), FAILED);
292+
assertEquals(queryInfo.getErrorCode(), ABANDONED_QUERY.toErrorCode());
293+
assertEquals(queryManager.getQuerySession(queryId).getAccessControlContext().getSchema(), session.getSchema());
294+
assertEquals(queryManager.getQuerySession(queryId).getAccessControlContext().getCatalog(), session.getCatalog());
295+
}
296+
}
297+
276298
@Test
277299
public void testQueryCountMetrics()
278300
throws Exception

0 commit comments

Comments
 (0)