Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 9 additions & 0 deletions changelog/unreleased/cli-configurable-timeouts.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
# See https://github.com/apache/solr/blob/main/dev-docs/changelog.adoc
title: bin/solr CLI commands now fail fast (3s connect / 30s idle) against an unresponsive
node instead of inheriting SolrJ's 60s/600s bulk-indexing defaults.
type: changed
authors:
- name: Eric Pugh
links:
- name: PR#4955
url: https://github.com/apache/solr/pull/4955
18 changes: 17 additions & 1 deletion solr/core/src/java/org/apache/solr/cli/CLIUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,16 @@ private CLIUtils() {}
private static final long MAX_WAIT_FOR_CORE_LOAD_NANOS =
TimeUnit.NANOSECONDS.convert(1, TimeUnit.MINUTES);

/**
* Connect and idle timeouts used for CLI-initiated Solr connections. These are much shorter than
* {@link org.apache.solr.client.solrj.impl.SolrHttpConstants}' defaults, which are sized for
* long-running requests like bulk indexing or replica recovery; a CLI command run by a human at a
* terminal should fail fast instead of hanging for minutes against an unresponsive node.
*/
public static final int CLI_CONNECTION_TIMEOUT_SECONDS = 3;

public static final int CLI_IDLE_TIMEOUT_SECONDS = 30;

private static CloudSolrClient.CloudSolrClientConnection resolveSolrConnectionFromCli(
CommandLine cli) throws IOException {
String solrConnection =
Expand Down Expand Up @@ -146,6 +156,8 @@ public static SolrClient getSolrClient(String solrUrl, String credentials, boole
var builder =
new HttpJettySolrClient.Builder(solrUrl)
.withMaxConnectionsPerHost(32)
.withIdleTimeout(CLI_IDLE_TIMEOUT_SECONDS, TimeUnit.SECONDS)
.withConnectionTimeout(CLI_CONNECTION_TIMEOUT_SECONDS, TimeUnit.SECONDS)
.withKeyStoreReloadInterval(-1, TimeUnit.SECONDS)
.withOptionalBasicAuthCredentials(credentials);

Expand Down Expand Up @@ -258,7 +270,11 @@ public static String solrUrlFromConnection(
if (!solrConnection.isZookeeper()) {
return normalizeSolrUrl(solrConnection.quorumItems().get(0), false);
}
var builder = new HttpJettySolrClient.Builder().withOptionalBasicAuthCredentials(credentials);
var builder =
new HttpJettySolrClient.Builder()
.withIdleTimeout(CLI_IDLE_TIMEOUT_SECONDS, TimeUnit.SECONDS)
.withConnectionTimeout(CLI_CONNECTION_TIMEOUT_SECONDS, TimeUnit.SECONDS)
.withOptionalBasicAuthCredentials(credentials);
try (CloudSolrClient cloudSolrClient = getCloudSolrClient(solrConnection, builder)) {
Set<String> liveNodes = cloudSolrClient.getClusterState().getLiveNodes();
if (liveNodes.isEmpty())
Expand Down
6 changes: 5 additions & 1 deletion solr/core/src/java/org/apache/solr/cli/ExportTool.java
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,11 @@ DocsSink getSink() {
abstract void exportDocs() throws Exception;

void fetchUniqueKey() throws SolrServerException, IOException {
var builder = new HttpJettySolrClient.Builder().withOptionalBasicAuthCredentials(credentials);
var builder =
new HttpJettySolrClient.Builder()
.withIdleTimeout(CLIUtils.CLI_IDLE_TIMEOUT_SECONDS, TimeUnit.SECONDS)
.withConnectionTimeout(CLIUtils.CLI_CONNECTION_TIMEOUT_SECONDS, TimeUnit.SECONDS)
.withOptionalBasicAuthCredentials(credentials);

solrClient =
new CloudSolrClient.Builder(List.of(baseurl)).withHttpClientBuilder(builder).build();
Expand Down
6 changes: 5 additions & 1 deletion solr/core/src/java/org/apache/solr/cli/HealthcheckTool.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
Expand Down Expand Up @@ -93,7 +94,10 @@ public void runImpl(CommandLine cli) throws Exception {
cli.getOptionValue(COLLECTION_NAME_OPTION),
cli.getOptionValue(CommonCLIOptions.CREDENTIALS_OPTION));
var builder =
new HttpJettySolrClient.Builder().withOptionalBasicAuthCredentials(params.credentials());
new HttpJettySolrClient.Builder()
.withIdleTimeout(CLIUtils.CLI_IDLE_TIMEOUT_SECONDS, TimeUnit.SECONDS)
.withConnectionTimeout(CLIUtils.CLI_CONNECTION_TIMEOUT_SECONDS, TimeUnit.SECONDS)
.withOptionalBasicAuthCredentials(params.credentials());
try (var cloudSolrClient = CLIUtils.getCloudSolrClient(solrConnection, builder)) {
echoIfVerbose("Connecting to Solr at " + solrConnection.toString());
runCloudTool(cloudSolrClient, params);
Expand Down
2 changes: 2 additions & 0 deletions solr/core/src/java/org/apache/solr/cli/PostLogsTool.java
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,8 @@ public void runCommand(String baseUrl, String root, String credentials) throws I
var builder =
new HttpJettySolrClient.Builder(URLUtil.extractBaseUrl(baseUrl))
.withDefaultCollection(URLUtil.extractCoreFromCoreUrl(baseUrl))
.withIdleTimeout(CLIUtils.CLI_IDLE_TIMEOUT_SECONDS, TimeUnit.SECONDS)
.withConnectionTimeout(CLIUtils.CLI_CONNECTION_TIMEOUT_SECONDS, TimeUnit.SECONDS)
.withKeyStoreReloadInterval(-1, TimeUnit.SECONDS)
.withOptionalBasicAuthCredentials(credentials);
try (SolrClient client = builder.build()) {
Expand Down
6 changes: 5 additions & 1 deletion solr/core/src/java/org/apache/solr/cli/StreamTool.java
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
Expand Down Expand Up @@ -303,7 +304,10 @@ void runStream(
private StreamContext createStreamContext(
CloudSolrClient.CloudSolrClientConnection solrConnection, String credentials) {
var jettyClientBuilder = new HttpJettySolrClient.Builder();
jettyClientBuilder.withOptionalBasicAuthCredentials(credentials);
jettyClientBuilder
.withIdleTimeout(CLIUtils.CLI_IDLE_TIMEOUT_SECONDS, TimeUnit.SECONDS)
.withConnectionTimeout(CLIUtils.CLI_CONNECTION_TIMEOUT_SECONDS, TimeUnit.SECONDS)
.withOptionalBasicAuthCredentials(credentials);
HttpJettySolrClient client = jettyClientBuilder.build();

// subclass so we can ensure our client is closed when the cache is closed
Expand Down
Loading