mirror of
https://github.com/hanzoai/tasks.git
synced 2026-10-04 02:04:03 +00:00
## What changed? This PR introduces two key features to enable out-of-the-box Nexus functionality with zero configuration: 1. **Always allow `temporal://system` callback URLs**: The `component.callbacks.allowedAddresses` configuration now automatically allows `temporal://system` URLs regardless of configured address rules. This special scheme+host combination bypasses normal URL validation and is always permitted. 2. **New UseSystemCallbackURL toggle**: Added `component.nexusoperations.useSystemCallbackURL` dynamic config that controls callback URL generation for worker targets: - When `false` (default): Uses the existing callback URL template approach - When `true`: Worker targets automatically get `temporal://system` - External targets continue to use template-generated URLs regardless of this setting - NOTE: if this toggle is `true` HTTPCallerProvider must be able to route internal requests based on theSource and Token headers. It should also override the path to `/nexus/callback`. See the HTTPCallerProvider code changes here. 3. **Callback URL Validation** has been refactored. The `AddressMatchRules` struct now includes a `Validate` method that handles the special `temporal://system` case and applies configured rules for other URLs. 4. **Callback Source Header**: will no longer be populated for external Targets. ## Why? Once `component.nexusoperations.useSystemCallbackURL` is enabled by default in a future release, these changes will allow Self-Hosted Temporal Servers to support Nexus with zero dynamic configuration See this issue: https://github.com/temporalio/temporal/issues/8298 ## How did you test it? - [x] built - [x] run locally and tested manually - [x] covered by existing tests - [x] added new unit test(s) - [x] added new functional test(s) --------- Co-authored-by: alex stanfield <[email protected]> Co-authored-by: Roey Berman <[email protected]>
72 lines
2.4 KiB
Go
72 lines
2.4 KiB
Go
package callbacks
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"go.temporal.io/server/common"
|
|
"go.temporal.io/server/common/cluster"
|
|
"go.temporal.io/server/common/log"
|
|
"go.temporal.io/server/common/log/tag"
|
|
"go.temporal.io/server/common/nexus"
|
|
)
|
|
|
|
// Header key used to identify callbacks that originate from and target the same cluster.
|
|
// Note: this is the nexusoperations.NexusCallbackSourceHeader stripped of Nexus-Callback-
|
|
const callbackSourceHeader = "source"
|
|
|
|
func routeRequest(
|
|
r *http.Request,
|
|
clusterMetadata cluster.Metadata,
|
|
httpClientCache *cluster.FrontendHTTPClientCache,
|
|
defaultClient *http.Client,
|
|
localClient *common.FrontendHTTPClient,
|
|
logger log.Logger,
|
|
) (*http.Response, error) {
|
|
// This source header is populated in nexusoperations/executors (via the ClientProvider) for worker targets
|
|
// if this header is not populated then we assume it's and external target.
|
|
if r.Header == nil || r.Header.Get(callbackSourceHeader) == "" {
|
|
return defaultClient.Do(r)
|
|
}
|
|
// If we got here, we assume that the endpoint in the original call was a worker target, and we should route
|
|
// internally, either to a local frontend, or one of the other connected clusters' frontends.
|
|
var frontendClient *common.FrontendHTTPClient
|
|
callbackSource := r.Header.Get(callbackSourceHeader)
|
|
for clusterName, clusterInfo := range clusterMetadata.GetAllClusterInfo() {
|
|
if callbackSource == clusterInfo.ClusterID {
|
|
if clusterMetadata.GetCurrentClusterName() == clusterName {
|
|
frontendClient = localClient
|
|
} else {
|
|
fec, err := httpClientCache.Get(clusterName)
|
|
if err != nil {
|
|
logger.Warn(
|
|
"HTTPCallerProvider unable to get FrontendHTTPClient for callback target cluster. Using local HTTP Client.",
|
|
tag.SourceCluster(clusterMetadata.GetCurrentClusterName()),
|
|
tag.TargetCluster(clusterName),
|
|
tag.Error(err),
|
|
)
|
|
frontendClient = localClient
|
|
} else {
|
|
frontendClient = fec
|
|
}
|
|
}
|
|
break
|
|
}
|
|
}
|
|
if frontendClient == nil {
|
|
// This can happen when a cluster is disconnected.
|
|
logger.Warn(
|
|
"HTTPCallerProvider unable to find the target cluster. Using local HTTP Client.",
|
|
tag.SourceCluster(clusterMetadata.GetCurrentClusterName()),
|
|
)
|
|
frontendClient = localClient
|
|
}
|
|
|
|
if r.URL.String() == nexus.SystemCallbackURL {
|
|
r.URL.Path = nexus.PathCompletionCallbackNoIdentifier
|
|
}
|
|
r.URL.Scheme = frontendClient.Scheme
|
|
r.URL.Host = frontendClient.Address
|
|
r.Host = frontendClient.Address
|
|
return frontendClient.Do(r)
|
|
}
|