Skip to content

Conversation

JeremyDahlgren
Copy link
Contributor

This is the first in a series of PRs to refactor the RemoteClusterService to support multi-project. This first PR uses the DefaultProjectResolver.INSTANCE in the constructor. A follow up PR will handle refactoring needed to pass in the ProjectResolver in the constructor. Other follow up PRs will handle refactoring RemoteClusterAware.updateRemoteCluster() and other settings related methods that require a project ID to be provided.

Relates: ES-11576

This is the first in a series of PRs to refactor the
RemoteClusterService to support multi-project.  This
first PR uses the DefaultProjectResolver.INSTANCE in
the constructor.  A follow up PR will handle refactoring
needed to pass inthe ProjectResolver in the constructor.
Other follow up PRs will handle refactoring
RemoteClusterAware.updateRemoteCluster() and other
settings related methods that require a project ID to
be provided.
@JeremyDahlgren JeremyDahlgren requested a review from ywangd July 25, 2025 01:36
@JeremyDahlgren JeremyDahlgren added :Distributed Coordination/Network Http and internode communication implementations >refactoring Team:Distributed Coordination Meta label for Distributed Coordination team v9.2.0 labels Jul 25, 2025
Copy link
Member

@ywangd ywangd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for working on this. I left some comments.

* Returns the map of connections for the given {@link ProjectId}.
*/
private Map<String, RemoteClusterConnection> getConnectionsMap(ProjectId projectId) {
return remoteClusters.computeIfAbsent(projectId, unused -> ConcurrentCollections.newConcurrentMap());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we go with my previous suggestion, this needs to change as well since immutable map does not support computeIfAbsent. So something like the following would be necessary

Suggested change
return remoteClusters.computeIfAbsent(projectId, unused -> ConcurrentCollections.newConcurrentMap());
return projectResolver.supportsMultipleProjects() ? remoteClusters.computeIfAbsent(projectId, unused -> ConcurrentCollections.newConcurrentMap()) : remoteClusters.get(projectId);

We can also assert projectId is default when projectResolver.supportsMultipleProjects() == false and vice versa.

Comment on lines 294 to 296
public Set<String> getRegisteredRemoteClusterNames() {
return remoteClusters.keySet();
return getConnectionsMap().keySet();
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Methods like this one relies on the project context configured correctly by the caller. Not an issue for non-MP. But we will need to double check for MP. Probably worth to log an issue so that we don't forget.

This method is used by TransportClusterStatsAction which can be argued as cluster scoped. In that case, we'd need loop through all projects for this method. This will be a big change since it affects REST API output. So I think we can go with this now and revisit it later similar to how we did for indices stats and add a fix annotation there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the fix annotation here and in a few other places. It might be good to review the package-access test methods as well as some of the other public methods that use the connections map and see if we can reduce the overall API surface area. It would help with reasoning about all the multi-project use cases. I can submit small separate PRs if I find some scenarios where we'd get some benefit from refactoring.

Comment on lines 463 to 466
@FixForMultiProject(description = "Refactor to provide the project ID that the linked alias and settings are associated with.")
@Override
protected void updateRemoteCluster(String clusterAlias, Settings settings) {
final var projectId = projectResolver.getProjectId();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is called by settings applier which does not have project context today so that resolver won't work for MP. Can we link an issue (if there is one for settings changes) here to remind us? Maybe the fix annotation is for this purpose? If so, I'd prefer we move it directly above projectId assignment line.

"this node does not have the " + DiscoveryNodeRole.REMOTE_CLUSTER_CLIENT_ROLE.roleName() + " role"
);
}
final var projectConnectionsMap = getConnectionsMap();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if async search would provide the necessary project context.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added the fix annotation here as well.

@JeremyDahlgren JeremyDahlgren marked this pull request as ready for review July 25, 2025 21:21
@elasticsearchmachine
Copy link
Collaborator

Pinging @elastic/es-distributed-coordination (Team:Distributed Coordination)

Copy link
Member

@ywangd ywangd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have one comment about sticking to one way of handling ProjectId for public methods.

Comment on lines 476 to 477
@FixForMultiProject(description = "ES-12270: Add a parameter for the project ID associated with the linked alias and settings.")
final var projectId = projectResolver.getProjectId();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we are not entirely sure whether the projectId will be passed-in explicitly or resolved from context since this is still being discussed over #131637

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I adjusted the annotation descriptions so we refactor if needed. It is sounding like the preference will be to try to use the project resolver, per Mark's comment in #131637.

Comment on lines 381 to 382
@FixForMultiProject(description = "Refactor method parameters to supply the project ID.")
final var projectId = projectResolver.getProjectId();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is ideal if all public methods (except those targeting all projects) of this class have a consistent way for handling ProjectId, either:

  1. Take a ProjectId parameter
  2. Or, resolving from threadContext with projectResolver

Otherwise it's rather difficult to reason with the behaviour. Which one is your preference? My current thinking is that we should go with the 2nd option [0] (private methods can sure and will likely need to take ProjectId parameter). Right now we have a mixed usages across all public methods depending wether it ends up calling getConnectionsMapForCurrentProject or getConnectionsMapForProject. I'd prefer we tighten them up.

[0] An outstanding issue is whether project settings update are performed with context, i.e. depending on the outcome of #131637. It's possible that we will go with the threadContext path. Even if we don't, it's reasonable to make those as exception since they are mutating methods while other reading methods should stick to one convention.

Copy link
Contributor Author

@JeremyDahlgren JeremyDahlgren Jul 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I updated the annotations and changed one method where we could call getConnectionsMapForCurrentProject() instead of getConnectionsMapForProject().

The only places outside of getConnectionsMapForCurrentProject() where the project resolver is used to get the project ID is where we need it ahead of time for logging. So right now it should be consistent that the current plan is to obtain the project ID via the resolver. There are a few fix annotations for methods where we would need to revisit use cases to determine if cluster-wide versions need to be supported, or if supporting context would not be available for use in the resolver.

JeremyDahlgren added a commit to JeremyDahlgren/elasticsearch that referenced this pull request Jul 28, 2025
This change eliminates or moves the following methods from
RemoteClusterService:
  isCrossClusterSearchEnabled()
  isRemoteNodeConnected()
  isRemoteClusterRegistered()

This is part of an effort to reduce the API surface area
of RemoteClusterService.

Relates: elastic#131894, elastic#131948
JeremyDahlgren added a commit that referenced this pull request Jul 30, 2025
This change eliminates or moves the following methods from
RemoteClusterService:
  isCrossClusterSearchEnabled()
  isRemoteNodeConnected()
  isRemoteClusterRegistered()

This is part of an effort to reduce the API surface area
of RemoteClusterService.

Relates: #131894, #131948
Copy link
Member

@ywangd ywangd left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

Comment on lines -427 to -433
/**
* This method updates the list of remote clusters. It's intended to be used as an update consumer on the settings infrastructure
*
* @param clusterAlias a cluster alias to discovery node mapping representing the remote clusters seeds nodes
* @param newSettings the updated settings for the remote connection
* @param listener a listener invoked once every configured cluster has been connected to
*/
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we salvage javadocs for the parameters to the overloaded method below it, i.e. this method

private synchronized void updateRemoteCluster(
        ProjectId projectId,
        String clusterAlias,
        Settings newSettings,
        boolean forceRebuild,
        ActionListener<RemoteClusterConnectionStatus> listener
    )

?

Comment on lines +470 to 471
@FixForMultiProject(description = "Refactor to supply the project ID associated with the alias and settings, or eliminate this method.")
void updateRemoteCluster(String clusterAlias, Settings newSettings, ActionListener<RemoteClusterConnectionStatus> listener) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IIUC, this method only has test usages after this PR. So yeah I'd prefer to remove it eventually.

afoucret pushed a commit to afoucret/elasticsearch that referenced this pull request Jul 31, 2025
…132037)

This change eliminates or moves the following methods from
RemoteClusterService:
  isCrossClusterSearchEnabled()
  isRemoteNodeConnected()
  isRemoteClusterRegistered()

This is part of an effort to reduce the API surface area
of RemoteClusterService.

Relates: elastic#131894, elastic#131948
@JeremyDahlgren JeremyDahlgren merged commit 4be260a into elastic:main Jul 31, 2025
33 checks passed
smalyshev pushed a commit to smalyshev/elasticsearch that referenced this pull request Jul 31, 2025
…132037)

This change eliminates or moves the following methods from
RemoteClusterService:
  isCrossClusterSearchEnabled()
  isRemoteNodeConnected()
  isRemoteClusterRegistered()

This is part of an effort to reduce the API surface area
of RemoteClusterService.

Relates: elastic#131894, elastic#131948
smalyshev pushed a commit to smalyshev/elasticsearch that referenced this pull request Jul 31, 2025
This is the first in a series of PRs to refactor the
RemoteClusterService to support multi-project.  This
first PR uses the DefaultProjectResolver.INSTANCE in
the constructor.  A follow up PR will handle refactoring
needed to pass in the ProjectResolver in the constructor.
Other follow up PRs will handle refactoring
RemoteClusterAware.updateRemoteCluster() and other
settings related methods that require a project ID to
be provided.
szybia added a commit to szybia/elasticsearch that referenced this pull request Aug 15, 2025
* upstream/main: (822 commits)
  Improve Semantic Text Exists Query Tests (elastic#132283)
  Make hierarchical k-means over centroids cheaper (elastic#132316)
  Remove unnecessary listener.delegateFailure in IndexShard#ensureMutable (elastic#132294)
  Add missing release note (elastic#132319)
  Unmute elastic#131803 (elastic#132295)
  Include bytes for live docs in ShardFieldStats (elastic#132232)
  Fix default missing index sort value of data_nanos pre 7.14 (elastic#132162)
  [DiskBBQ] Quantize centroids using 7 bits instead of 4 bits (elastic#132261)
  Use panamized version for windows in Int7VectorScorer (elastic#132311)
  Mute org.elasticsearch.xpack.ml.integration.AutodetectMemoryLimitIT testTooManyByAndOverFields elastic#132310
  Mute org.elasticsearch.xpack.ml.integration.AutodetectMemoryLimitIT testManyDistinctOverFields elastic#132308
  Update 8.17 version to 8.17.10 (elastic#132303)
  Mute org.elasticsearch.datastreams.DataStreamsClientYamlTestSuiteIT test {p0=data_stream/10_basic/Create hidden data stream with match all template} elastic#132298
  Add random queries to logsdb data generation tests (elastic#132109)
  ES|QL Inference runner refactoring (elastic#131986)
  Add basic example to linear-retriever.md (elastic#132196)
  Refactor RemoteClusterService to be multi-project aware (elastic#131894)
  ESQL: Mark csv-spec tests (elastic#132098)
  Mute org.elasticsearch.common.logging.JULBridgeTests testThrowable elastic#132280
  Bump versions after 8.19.0 release
  ...
JeremyDahlgren added a commit to JeremyDahlgren/elasticsearch that referenced this pull request Aug 15, 2025
Follow up to work done in elastic#131894 to make RemoteClusterService
multi-project aware.  This task plumbs the ProjectResolver down
into the RemoteClusterService from NodeConstruction.

Resolves: ES-12572
JeremyDahlgren added a commit to JeremyDahlgren/elasticsearch that referenced this pull request Aug 15, 2025
Follow up to work done in elastic#131894 to make RemoteClusterService
multi-project aware.  This task plumbs the ProjectResolver down
into the RemoteClusterService from NodeConstruction.

Resolves: ES-12572
JeremyDahlgren added a commit to JeremyDahlgren/elasticsearch that referenced this pull request Aug 15, 2025
Follow up to work done in elastic#131894 to make RemoteClusterService
multi-project aware.  This task plumbs the ProjectResolver down
into the RemoteClusterService from NodeConstruction.

Resolves: ES-12572
JeremyDahlgren added a commit that referenced this pull request Aug 28, 2025
Follow up to work done in #131894 to make RemoteClusterService
multi-project aware.  This task plumbs the ProjectResolver down
into the RemoteClusterService from NodeConstruction.

Resolves: ES-12572
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

:Distributed Coordination/Network Http and internode communication implementations >refactoring Team:Distributed Coordination Meta label for Distributed Coordination team v9.2.0

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants