Files
tasks/common/worker_versioning/routing_info_cache.go
1e31c76ed1 Versioning cherry-pick for OSS v1.30.2 (#9543)
## What changed?
Cherry-pick versioning PRs
- #9168
  - Cache for system protection
- #9262 
  - Cache for system protection
- #9239 
- Critical PR to enable sending `TargetVersionChanged` flag for
Upgrade-on-CaN feature
- #9147 
- Tracks version drainage properly when version receives workflows via
`VersioningOverride`. Needed for automated worker controllers to
correctly scale versioned workers that received workflows via
`VersioningOverride`.
- #9300 
- Needed for `approximate_backlog_count` metric to track Current and
Ramping version tasks correctly
- #9316 
- Needed for `approximate_backlog_count` metric to track Current and
Ramping version tasks correctly
- #8957 
- Contains minor metric improvement. Included because it adds a test
harness that is used in the two metrics PRs above
- #9250 
  - Bug fix of task rescheduling edge case during AutoUpgrade Transition

## Why?
For OSS v1.30.2

## How did you test it?
- [x] built
- [ ] run locally and tested manually
- [x] covered by existing tests
- [ ] added new unit test(s)
- [ ] added new functional test(s)





---

> [!NOTE]
> **Medium Risk**
> Touches history/matching worker-versioning paths, adding new caches
and changing workflow task/start handling and backlog metric emission;
incorrect caching or signaling could affect dispatch/upgrade behavior
and observability.
> 
> **Overview**
> Adds new worker-versioning protections and upgrade signaling: workflow
task started events now persist a
`workflow_task_target_worker_deployment_version_changed` flag (and emit
a new `workflow_target_version_changed_count` metric) under a new
`EnableSendTargetVersionChanged` dynamic config.
> 
> Introduces two new caches with metrics and dynamic config knobs: a
`RoutingInfoCache` to avoid repeated `GetTaskQueueUserData` lookups
during activity start/transition logic, and a `ReactivationSignalCache`
plus `EnableVersionReactivationSignals` to dedupe and asynchronously
send “reactivation” signals when workflows are pinned (via
start/signal-with-start/reset/update-options) to potentially
drained/inactive worker versions.
> 
> Extends matching backlog metrics to support version-attributed
reporting by adding `BacklogMetricsEmitInterval` and switching queue DB
emission to *physical* backlog gauges (`physical_approximate_backlog_*`)
when attribution is enabled, while keeping legacy gauges when disabled.
> 
> Adds frontend scaffolding for a new visibility RPC `CountSchedules`
(client plumbing, interception/metadata/quota wiring) but leaves the
frontend handler unimplemented, and bumps `go.temporal.io/api` to
`v1.62.2`.
> 
> <sup>Written by [Cursor
Bugbot]() for commit
cb8ae14c86666654c51dd66ae91cb225722e1ba7. This will update automatically
on new commits. Configure
[here]().</sup>

---------

Co-authored-by: Shahab Tajik <[email protected]>
Co-authored-by: Shivam <[email protected]>
2026-03-17 17:19:47 -05:00

133 lines
3.8 KiB
Go

//nolint:staticcheck
package worker_versioning
import (
enumspb "go.temporal.io/api/enums/v1"
deploymentspb "go.temporal.io/server/api/deployment/v1"
"go.temporal.io/server/common/cache"
"go.temporal.io/server/common/metrics"
)
// RoutingInfoCache is used to cache results of GetTaskQueueUserData
// calls followed by CalculateTaskQueueVersioningInfo computation.
//
// Implementations are expected to be safe for concurrent use.
type (
RoutingInfo struct {
Current *deploymentspb.WorkerDeploymentVersion
CurrentRevisionNumber int64
Ramping *deploymentspb.WorkerDeploymentVersion
RampPercentage float32
RampingRevisionNumber int64
}
RoutingInfoCache interface {
// Get returns the cached routing info. ok=false means there was no cached value.
Get(
namespaceID string,
taskQueue string,
taskQueueType enumspb.TaskQueueType,
) (RoutingInfo, bool)
Put(
namespaceID string,
taskQueue string,
taskQueueType enumspb.TaskQueueType,
current *deploymentspb.WorkerDeploymentVersion,
currentRevisionNumber int64,
ramping *deploymentspb.WorkerDeploymentVersion,
rampPercentage float32,
rampingRevisionNumber int64,
)
}
routingInfoCacheKey struct {
namespaceID string
taskQueue string
taskQueueType enumspb.TaskQueueType
}
routingInfoCacheValue struct {
current *deploymentspb.WorkerDeploymentVersion
currentRevisionNumber int64
ramping *deploymentspb.WorkerDeploymentVersion
rampPercentage float32
rampingRevisionNumber int64
}
RoutingInfoCacheImpl struct {
cache.Cache
metricsHandler metrics.Handler
}
)
// NewRoutingInfoCache wraps the provided cache with a typed API and metrics.
func NewRoutingInfoCache(c cache.Cache, metricsHandler metrics.Handler) RoutingInfoCache {
h := metricsHandler.WithTags(metrics.CacheTypeTag(metrics.RoutingInfoCacheTypeTagValue))
return &RoutingInfoCacheImpl{
Cache: c,
metricsHandler: h,
}
}
func (c *RoutingInfoCacheImpl) Get(
namespaceID string,
taskQueue string,
taskQueueType enumspb.TaskQueueType,
) (RoutingInfo, bool) {
handler := c.metricsHandler.WithTags(metrics.OperationTag(metrics.RoutingInfoCacheGetScope), metrics.NamespaceIDTag(namespaceID))
metrics.CacheRequests.With(handler).Record(1)
key := routingInfoCacheKey{
namespaceID: namespaceID,
taskQueue: taskQueue,
taskQueueType: taskQueueType,
}
v := c.Cache.Get(key)
if v == nil {
metrics.CacheMissCounter.With(handler).Record(1)
return RoutingInfo{}, false
}
value, ok := v.(routingInfoCacheValue)
if !ok {
// Unexpected type: treat as miss to avoid false positives.
metrics.CacheMissCounter.With(handler).Record(1)
return RoutingInfo{}, false
}
return RoutingInfo{
Current: value.current,
CurrentRevisionNumber: value.currentRevisionNumber,
Ramping: value.ramping,
RampPercentage: value.rampPercentage,
RampingRevisionNumber: value.rampingRevisionNumber,
}, true
}
func (c *RoutingInfoCacheImpl) Put(
namespaceID string,
taskQueue string,
taskQueueType enumspb.TaskQueueType,
current *deploymentspb.WorkerDeploymentVersion,
currentRevisionNumber int64,
ramping *deploymentspb.WorkerDeploymentVersion,
rampPercentage float32,
rampingRevisionNumber int64,
) {
handler := c.metricsHandler.WithTags(metrics.OperationTag(metrics.RoutingInfoCachePutScope), metrics.NamespaceIDTag(namespaceID))
metrics.CacheRequests.With(handler).Record(1)
key := routingInfoCacheKey{
namespaceID: namespaceID,
taskQueue: taskQueue,
taskQueueType: taskQueueType,
}
value := routingInfoCacheValue{
current: current,
currentRevisionNumber: currentRevisionNumber,
ramping: ramping,
rampPercentage: rampPercentage,
rampingRevisionNumber: rampingRevisionNumber,
}
c.Cache.Put(key, value)
}