mirror of
https://github.com/hanzoai/tasks.git
synced 2026-10-04 02:04:03 +00:00
## 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]>
163 lines
4.6 KiB
Go
163 lines
4.6 KiB
Go
package history
|
|
|
|
import (
|
|
"sync/atomic"
|
|
"testing"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
"go.opentelemetry.io/otel/trace"
|
|
"go.temporal.io/server/chasm"
|
|
"go.temporal.io/server/client"
|
|
"go.temporal.io/server/common/clock"
|
|
"go.temporal.io/server/common/cluster"
|
|
"go.temporal.io/server/common/dynamicconfig"
|
|
"go.temporal.io/server/common/log"
|
|
"go.temporal.io/server/common/membership"
|
|
"go.temporal.io/server/common/metrics"
|
|
"go.temporal.io/server/common/namespace"
|
|
"go.temporal.io/server/common/persistence"
|
|
"go.temporal.io/server/common/persistence/serialization"
|
|
"go.temporal.io/server/common/persistence/visibility/manager"
|
|
"go.temporal.io/server/common/resource"
|
|
"go.temporal.io/server/common/sdk"
|
|
"go.temporal.io/server/common/telemetry"
|
|
"go.temporal.io/server/common/worker_versioning"
|
|
"go.temporal.io/server/service/history/archival"
|
|
"go.temporal.io/server/service/history/configs"
|
|
"go.temporal.io/server/service/history/replication/eventhandler"
|
|
"go.temporal.io/server/service/history/shard"
|
|
"go.temporal.io/server/service/history/tasks"
|
|
"go.temporal.io/server/service/history/workflow"
|
|
"go.temporal.io/server/service/history/workflow/cache"
|
|
"go.uber.org/fx"
|
|
"go.uber.org/mock/gomock"
|
|
)
|
|
|
|
// TestQueueModule_ArchivalQueue tests that the archival queue is created if and only if the task category exists.
|
|
func TestQueueModule_ArchivalQueue(t *testing.T) {
|
|
for _, c := range []moduleTestCase{
|
|
{
|
|
Name: "Archival disabled",
|
|
CategoryExists: false,
|
|
ExpectArchivalQueue: false,
|
|
},
|
|
{
|
|
Name: "Archival enabled",
|
|
CategoryExists: true,
|
|
ExpectArchivalQueue: true,
|
|
},
|
|
} {
|
|
c := c
|
|
t.Run(c.Name, c.Run)
|
|
}
|
|
}
|
|
|
|
// moduleTestCase is a test case for the QueueModule.
|
|
type moduleTestCase struct {
|
|
Name string
|
|
ExpectArchivalQueue bool
|
|
CategoryExists bool
|
|
}
|
|
|
|
// Run runs the test case.
|
|
func (c *moduleTestCase) Run(t *testing.T) {
|
|
|
|
controller := gomock.NewController(t)
|
|
dependencies := getModuleDependencies(controller, c)
|
|
var factories []QueueFactory
|
|
|
|
app := fx.New(
|
|
dependencies,
|
|
QueueModule,
|
|
fx.Invoke(func(params QueueFactoriesLifetimeHookParams) {
|
|
factories = params.Factories
|
|
}),
|
|
)
|
|
|
|
require.NoError(t, app.Err())
|
|
require.NotNil(t, factories)
|
|
var (
|
|
txq QueueFactory
|
|
tiq QueueFactory
|
|
viq QueueFactory
|
|
aq QueueFactory
|
|
)
|
|
for _, f := range factories {
|
|
switch f.(type) {
|
|
case *transferQueueFactory:
|
|
require.Nil(t, txq)
|
|
txq = f
|
|
case *timerQueueFactory:
|
|
require.Nil(t, tiq)
|
|
tiq = f
|
|
case *visibilityQueueFactory:
|
|
require.Nil(t, viq)
|
|
viq = f
|
|
case *archivalQueueFactory:
|
|
require.Nil(t, aq)
|
|
aq = f
|
|
}
|
|
}
|
|
require.NotNil(t, txq)
|
|
require.NotNil(t, tiq)
|
|
require.NotNil(t, viq)
|
|
if c.ExpectArchivalQueue {
|
|
require.NotNil(t, aq)
|
|
} else {
|
|
require.Nil(t, aq)
|
|
}
|
|
}
|
|
|
|
// getModuleDependencies returns an fx.Option that provides all the dependencies needed for the queue module.
|
|
func getModuleDependencies(controller *gomock.Controller, c *moduleTestCase) fx.Option {
|
|
cfg := configs.NewConfig(
|
|
dynamicconfig.NewNoopCollection(),
|
|
1,
|
|
)
|
|
clusterMetadata := cluster.NewMockMetadata(controller)
|
|
clusterMetadata.EXPECT().GetCurrentClusterName().Return("module-test-cluster-name").AnyTimes()
|
|
lazyLoadedOwnershipBasedQuotaScaler := shard.LazyLoadedOwnershipBasedQuotaScaler{
|
|
Value: &atomic.Value{},
|
|
}
|
|
registry := tasks.NewDefaultTaskCategoryRegistry()
|
|
if c.CategoryExists {
|
|
registry.AddCategory(tasks.CategoryArchival)
|
|
}
|
|
serializer := serialization.NewSerializer()
|
|
historyFetcher := eventhandler.NewMockHistoryPaginatedFetcher(controller)
|
|
return fx.Supply(
|
|
unusedDependencies{},
|
|
cfg,
|
|
fx.Annotate(registry, fx.As(new(tasks.TaskCategoryRegistry))),
|
|
fx.Annotate(metrics.NoopMetricsHandler, fx.As(new(metrics.Handler))),
|
|
fx.Annotate(log.NewTestLogger(), fx.As(new(log.SnTaggedLogger))),
|
|
fx.Annotate(clusterMetadata, fx.As(new(cluster.Metadata))),
|
|
lazyLoadedOwnershipBasedQuotaScaler,
|
|
fx.Annotate(serializer, fx.As(new(serialization.Serializer))),
|
|
fx.Annotate(historyFetcher, fx.As(new(eventhandler.HistoryPaginatedFetcher))),
|
|
fx.Annotate(telemetry.NoopTracerProvider, fx.As(new(trace.TracerProvider))),
|
|
)
|
|
}
|
|
|
|
// This is a struct that provides nil implementations of all the dependencies needed for the queue module that are not
|
|
// actually used.
|
|
type unusedDependencies struct {
|
|
fx.Out
|
|
|
|
clock.TimeSource
|
|
membership.ServiceResolver
|
|
namespace.Registry
|
|
client.Bean
|
|
sdk.ClientFactory
|
|
resource.MatchingRawClient
|
|
resource.HistoryRawClient
|
|
manager.VisibilityManager
|
|
archival.Archiver
|
|
workflow.RelocatableAttributesFetcher
|
|
persistence.HistoryTaskQueueManager
|
|
cache.Cache
|
|
chasm.Engine
|
|
ChasmRegistry *chasm.Registry
|
|
worker_versioning.VersionMembershipCache
|
|
}
|