mirror of
https://github.com/hanzoai/tasks.git
synced 2026-10-04 02:04:03 +00:00
## What changed? - I have made changes in the function that tells the SDK whether to scale their pollers up or down. The changes now shall consider the unversioned queue's backlog if a task is being dispatched to a poller of the current/ramping version. ## Why? - The main reason for this is that spooled tasks of the current/ramping version go to the unversioned queue's backlog. ## How did you test it? - [ ] built - [ ] run locally and tested manually - [ ] covered by existing tests - [ ] added new unit test(s) - [ ] added new functional test(s) ## Potential risks - None. --- > [!NOTE] > Improves autoscaling accuracy for versioned task queues by attributing unversioned backlog to promoted versions. > > - `physicalTaskQueueManager.MakePollerScalingDecision` now accepts `context.Context` and pulls stats via `partitionMgr.GetPhysicalQueueAdjustedStats(...)`, which derives per-queue `TaskQueueStats` from `Describe(...)` with deployment-aware build IDs > - New `taskQueuePartitionManagerImpl.GetPhysicalQueueAdjustedStats` adjusts stats for unversioned/current/ramping attribution; `MakePollerScalingDecision` logic updated to use `Get*` accessors and early-exit structure unchanged > - Interface and mocks updated for the new method signature; call sites updated (`PollTask`) to pass context > - Added integration tests verifying scale-up decisions for current and 100%-ramping deployment versions that absorb unversioned backlog; minor test update to include expected ramp percentage in worker versioning tests > > <sup>Written by [Cursor Bugbot]() for commit acf401fa931c8f22389ca8fb2625713fb6b6e308. This will update automatically on new commits. Configure [here]().</sup>
436 lines
17 KiB
Go
436 lines
17 KiB
Go
package tests
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/assert"
|
|
"github.com/stretchr/testify/require"
|
|
"github.com/stretchr/testify/suite"
|
|
commandpb "go.temporal.io/api/command/v1"
|
|
commonpb "go.temporal.io/api/common/v1"
|
|
deploymentpb "go.temporal.io/api/deployment/v1"
|
|
enumspb "go.temporal.io/api/enums/v1"
|
|
nexuspb "go.temporal.io/api/nexus/v1"
|
|
"go.temporal.io/api/operatorservice/v1"
|
|
taskqueuepb "go.temporal.io/api/taskqueue/v1"
|
|
"go.temporal.io/api/workflowservice/v1"
|
|
sdkclient "go.temporal.io/sdk/client"
|
|
"go.temporal.io/sdk/converter"
|
|
"go.temporal.io/server/common/dynamicconfig"
|
|
"go.temporal.io/server/common/payloads"
|
|
"go.temporal.io/server/common/util"
|
|
"go.temporal.io/server/components/nexusoperations"
|
|
"go.temporal.io/server/tests/testcore"
|
|
"google.golang.org/protobuf/types/known/durationpb"
|
|
)
|
|
|
|
type PollerScalingIntegSuite struct {
|
|
testcore.FunctionalTestBase
|
|
}
|
|
|
|
func (s *PollerScalingIntegSuite) mustToPayload(v any) *commonpb.Payload {
|
|
conv := converter.GetDefaultDataConverter()
|
|
payload, err := conv.ToPayload(v)
|
|
s.NoError(err)
|
|
return payload
|
|
}
|
|
|
|
func TestPollerScalingFunctionalSuite(t *testing.T) {
|
|
t.Parallel()
|
|
suite.Run(t, new(PollerScalingIntegSuite))
|
|
}
|
|
|
|
func (s *PollerScalingIntegSuite) SetupSuite() {
|
|
dynamicConfigOverrides := map[dynamicconfig.Key]any{
|
|
// Force one partition so we can reliably see the backlog
|
|
dynamicconfig.MatchingNumTaskqueueReadPartitions.Key(): 1,
|
|
dynamicconfig.MatchingNumTaskqueueWritePartitions.Key(): 1,
|
|
dynamicconfig.MatchingPollerScalingBacklogAgeScaleUp.Key(): 50 * time.Millisecond,
|
|
}
|
|
s.FunctionalTestBase.SetupSuiteWithCluster(testcore.WithDynamicConfigOverrides(dynamicConfigOverrides))
|
|
}
|
|
|
|
func (s *PollerScalingIntegSuite) TestPollerScalingSimpleBacklog() {
|
|
ctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
|
|
defer cancel()
|
|
|
|
tq := testcore.RandomizeStr(s.T().Name())
|
|
endpointName := testcore.RandomizedNexusEndpoint(s.T().Name())
|
|
s.OverrideDynamicConfig(
|
|
nexusoperations.CallbackURLTemplate,
|
|
"http://"+s.HttpAPIAddress()+"/namespaces/{{.NamespaceName}}/nexus/callback")
|
|
|
|
_, err := s.OperatorClient().CreateNexusEndpoint(ctx, &operatorservice.CreateNexusEndpointRequest{
|
|
Spec: &nexuspb.EndpointSpec{
|
|
Name: endpointName,
|
|
Target: &nexuspb.EndpointTarget{
|
|
Variant: &nexuspb.EndpointTarget_Worker_{
|
|
Worker: &nexuspb.EndpointTarget_Worker{
|
|
Namespace: s.Namespace().String(),
|
|
TaskQueue: tq,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
})
|
|
s.NoError(err)
|
|
|
|
// Queue up a couple workflows
|
|
for i := 0; i < 5; i++ {
|
|
_, err := s.SdkClient().ExecuteWorkflow(
|
|
ctx, sdkclient.StartWorkflowOptions{TaskQueue: tq}, "wf")
|
|
s.NoError(err)
|
|
}
|
|
|
|
// Poll for a task and see attached decision is to scale up b/c of backlog
|
|
feClient := s.FrontendClient()
|
|
// This needs to be done in an eventually loop because nexus endpoints don't become available immediately...
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
resp, err := feClient.PollWorkflowTaskQueue(ctx, &workflowservice.PollWorkflowTaskQueueRequest{
|
|
Namespace: s.Namespace().String(),
|
|
TaskQueue: &taskqueuepb.TaskQueue{Name: tq, Kind: enumspb.TASK_QUEUE_KIND_NORMAL},
|
|
})
|
|
require.NoError(t, err)
|
|
require.NotNil(t, resp.PollerScalingDecision)
|
|
require.GreaterOrEqual(t, int32(1), resp.PollerScalingDecision.PollRequestDeltaSuggestion)
|
|
|
|
// Start enough activities / nexus tasks to ensure we will see scale up decisions
|
|
commands := make([]*commandpb.Command, 0, 5)
|
|
for i := 0; i < 5; i++ {
|
|
commands = append(commands, &commandpb.Command{
|
|
CommandType: enumspb.COMMAND_TYPE_SCHEDULE_ACTIVITY_TASK,
|
|
Attributes: &commandpb.Command_ScheduleActivityTaskCommandAttributes{ScheduleActivityTaskCommandAttributes: &commandpb.ScheduleActivityTaskCommandAttributes{
|
|
ActivityId: fmt.Sprintf("%v", i),
|
|
ActivityType: &commonpb.ActivityType{Name: "test-activity-type"},
|
|
TaskQueue: &taskqueuepb.TaskQueue{Name: tq, Kind: enumspb.TASK_QUEUE_KIND_NORMAL},
|
|
Input: payloads.EncodeString("test-input"),
|
|
StartToCloseTimeout: durationpb.New(10 * time.Second),
|
|
}},
|
|
})
|
|
commands = append(commands, &commandpb.Command{
|
|
CommandType: enumspb.COMMAND_TYPE_SCHEDULE_NEXUS_OPERATION,
|
|
Attributes: &commandpb.Command_ScheduleNexusOperationCommandAttributes{
|
|
ScheduleNexusOperationCommandAttributes: &commandpb.ScheduleNexusOperationCommandAttributes{
|
|
Endpoint: endpointName,
|
|
Service: "service",
|
|
Operation: "operation",
|
|
Input: s.mustToPayload("input"),
|
|
},
|
|
},
|
|
},
|
|
)
|
|
}
|
|
_, err = feClient.RespondWorkflowTaskCompleted(ctx, &workflowservice.RespondWorkflowTaskCompletedRequest{
|
|
Identity: "test",
|
|
TaskToken: resp.TaskToken,
|
|
Commands: commands,
|
|
})
|
|
require.NoError(t, err)
|
|
}, 20*time.Second, 200*time.Millisecond)
|
|
|
|
// Wait to ensure add rate exceeds dispatch rate & backlog age grows
|
|
tqtyp := enumspb.TASK_QUEUE_TYPE_ACTIVITY
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
res, err := feClient.DescribeTaskQueue(ctx, &workflowservice.DescribeTaskQueueRequest{
|
|
Namespace: s.Namespace().String(),
|
|
TaskQueue: &taskqueuepb.TaskQueue{Name: tq},
|
|
ApiMode: enumspb.DESCRIBE_TASK_QUEUE_MODE_ENHANCED,
|
|
TaskQueueTypes: []enumspb.TaskQueueType{tqtyp},
|
|
ReportStats: true,
|
|
})
|
|
require.NoError(t, err)
|
|
stats := res.GetVersionsInfo()[""].TypesInfo[int32(tqtyp)].Stats
|
|
require.GreaterOrEqual(t, stats.ApproximateBacklogAge.AsDuration(), 200*time.Millisecond)
|
|
}, 20*time.Second, 200*time.Millisecond)
|
|
|
|
actResp, err := feClient.PollActivityTaskQueue(ctx, &workflowservice.PollActivityTaskQueueRequest{
|
|
Namespace: s.Namespace().String(),
|
|
TaskQueue: &taskqueuepb.TaskQueue{Name: tq, Kind: enumspb.TASK_QUEUE_KIND_NORMAL},
|
|
})
|
|
s.NoError(err)
|
|
s.NotNil(actResp.PollerScalingDecision)
|
|
s.Assert().GreaterOrEqual(int32(1), actResp.PollerScalingDecision.PollRequestDeltaSuggestion)
|
|
|
|
nexusResp, err := feClient.PollNexusTaskQueue(ctx, &workflowservice.PollNexusTaskQueueRequest{
|
|
Namespace: s.Namespace().String(),
|
|
TaskQueue: &taskqueuepb.TaskQueue{Name: tq, Kind: enumspb.TASK_QUEUE_KIND_NORMAL},
|
|
})
|
|
s.NoError(err)
|
|
s.NotNil(nexusResp.PollerScalingDecision)
|
|
}
|
|
|
|
// Here we verify that, even with multiple partitions, pollers see scaling decisions at least often enough
|
|
// that SDKs have information to work with. Benchmark style testing that exists on the SDK side is better at ensuring
|
|
// that the desired outcomes actually happen.
|
|
func (s *PollerScalingIntegSuite) TestPollerScalingDecisionsAreSeenProbabilistically() {
|
|
s.OverrideDynamicConfig(dynamicconfig.MatchingNumTaskqueueReadPartitions, 5)
|
|
s.OverrideDynamicConfig(dynamicconfig.MatchingNumTaskqueueWritePartitions, 5)
|
|
|
|
longctx, cancel := context.WithTimeout(context.Background(), 1*time.Minute)
|
|
defer cancel()
|
|
ctx, startWfCancel := context.WithCancel(longctx)
|
|
tq := testcore.RandomizeStr(s.T().Name())
|
|
|
|
// Fire off workflows until polling stops
|
|
go func() {
|
|
for {
|
|
_, _ = s.SdkClient().ExecuteWorkflow(
|
|
longctx, sdkclient.StartWorkflowOptions{TaskQueue: tq}, "wf")
|
|
select {
|
|
case <-ctx.Done():
|
|
return
|
|
case <-time.NewTimer(200 * time.Millisecond).C:
|
|
continue
|
|
}
|
|
}
|
|
}()
|
|
|
|
allScaleDecisions := make([]*taskqueuepb.PollerScalingDecision, 0, 15)
|
|
for i := 0; i < 15; i++ {
|
|
resp, _ := s.FrontendClient().PollWorkflowTaskQueue(longctx, &workflowservice.PollWorkflowTaskQueueRequest{
|
|
Namespace: s.Namespace().String(),
|
|
TaskQueue: &taskqueuepb.TaskQueue{Name: tq, Kind: enumspb.TASK_QUEUE_KIND_NORMAL},
|
|
})
|
|
if resp != nil {
|
|
allScaleDecisions = append(allScaleDecisions, resp.PollerScalingDecision)
|
|
}
|
|
// Poll slightly less frequently than we insert tasks
|
|
time.Sleep(300 * time.Millisecond) //nolint:forbidigo
|
|
}
|
|
startWfCancel()
|
|
|
|
// We must have seen at least a handful of non-nil scaling decisions
|
|
nonNilDecisions := util.FilterSlice(allScaleDecisions, func(d *taskqueuepb.PollerScalingDecision) bool { return d != nil })
|
|
s.Assert().GreaterOrEqual(len(nonNilDecisions), 3)
|
|
}
|
|
|
|
// The following tests verify poller scaling decisions work with worker-versioning based concepts.
|
|
func (s *PollerScalingIntegSuite) TestPollerScalingOnCurrentVersionConsidersUnversionedQueueBacklog() {
|
|
buildID := testcore.RandomizeStr("test-build-id")
|
|
ns := s.Namespace().String()
|
|
s.testPollerScalingOnPromotedVersionConsidersUnversionedQueueBacklog(
|
|
enumspb.WORKER_DEPLOYMENT_VERSION_STATUS_CURRENT,
|
|
buildID,
|
|
func(ctx context.Context, feClient workflowservice.WorkflowServiceClient, deploymentName, buildID string) error {
|
|
_, err := feClient.SetWorkerDeploymentCurrentVersion(ctx, &workflowservice.SetWorkerDeploymentCurrentVersionRequest{
|
|
Namespace: ns,
|
|
DeploymentName: deploymentName,
|
|
BuildId: buildID,
|
|
})
|
|
return err
|
|
},
|
|
)
|
|
}
|
|
|
|
func (s *PollerScalingIntegSuite) TestPollerScalingOnRampingVersionConsidersUnversionedQueueBacklog() {
|
|
// Use 100% ramp so the ramping version absorbs the entire unversioned backlog.
|
|
ns := s.Namespace().String()
|
|
|
|
const rampPercentage = float32(100)
|
|
rampingBuildID := testcore.RandomizeStr("test-ramping-build-id")
|
|
s.testPollerScalingOnPromotedVersionConsidersUnversionedQueueBacklog(
|
|
enumspb.WORKER_DEPLOYMENT_VERSION_STATUS_RAMPING,
|
|
rampingBuildID,
|
|
func(ctx context.Context, feClient workflowservice.WorkflowServiceClient, deploymentName, buildID string) error {
|
|
_, err := feClient.SetWorkerDeploymentRampingVersion(ctx, &workflowservice.SetWorkerDeploymentRampingVersionRequest{
|
|
Namespace: ns,
|
|
DeploymentName: deploymentName,
|
|
BuildId: buildID,
|
|
Percentage: rampPercentage,
|
|
})
|
|
return err
|
|
},
|
|
)
|
|
}
|
|
|
|
func (s *PollerScalingIntegSuite) testPollerScalingOnPromotedVersionConsidersUnversionedQueueBacklog(
|
|
expectedStatus enumspb.WorkerDeploymentVersionStatus,
|
|
testBuildID string,
|
|
promoteDeploymentVersion func(ctx context.Context, feClient workflowservice.WorkflowServiceClient, deploymentName, buildID string) error,
|
|
) {
|
|
// 1. Create a backlog of unversioned workflows.
|
|
// 2. Set the current/ramping version for a worker-deployment (depending on the test case)
|
|
// 3. Verify that the poller scaling decision reports a 1 since the deployment version (current/ramping) absorbs the unversioned backlog.
|
|
|
|
ctx, cancel := context.WithTimeout(context.Background(), 30*time.Second)
|
|
defer cancel()
|
|
|
|
tq := testcore.RandomizeStr("test-poller-scaling-tq")
|
|
feClient := s.FrontendClient()
|
|
|
|
const (
|
|
deploymentNamePrefix = "test-deployment"
|
|
)
|
|
deploymentName := testcore.RandomizeStr(deploymentNamePrefix)
|
|
|
|
// Queueing up unversioned workflows
|
|
for i := 0; i < 5; i++ {
|
|
_, err := s.SdkClient().ExecuteWorkflow(
|
|
ctx, sdkclient.StartWorkflowOptions{TaskQueue: tq}, "wf")
|
|
s.NoError(err)
|
|
}
|
|
|
|
// Start a workflow poller with DeploymentOptions so the deployment version is registered
|
|
type pollResult struct {
|
|
resp *workflowservice.PollWorkflowTaskQueueResponse
|
|
err error
|
|
}
|
|
pollResultCh := make(chan pollResult, 1)
|
|
|
|
go func() {
|
|
pollResp, err := feClient.PollWorkflowTaskQueue(ctx, &workflowservice.PollWorkflowTaskQueueRequest{
|
|
Namespace: s.Namespace().String(),
|
|
TaskQueue: &taskqueuepb.TaskQueue{Name: tq, Kind: enumspb.TASK_QUEUE_KIND_NORMAL},
|
|
DeploymentOptions: &deploymentpb.WorkerDeploymentOptions{
|
|
DeploymentName: deploymentName,
|
|
BuildId: testBuildID,
|
|
WorkerVersioningMode: enumspb.WORKER_VERSIONING_MODE_VERSIONED,
|
|
},
|
|
})
|
|
pollResultCh <- pollResult{resp: pollResp, err: err}
|
|
}()
|
|
|
|
// Also start a versioned activity poller so that the activity task queue is registered in the version
|
|
pollCtx, pollCancel := context.WithTimeout(context.Background(), 1*time.Minute)
|
|
go func() {
|
|
_, _ = feClient.PollActivityTaskQueue(pollCtx, &workflowservice.PollActivityTaskQueueRequest{
|
|
Namespace: s.Namespace().String(),
|
|
TaskQueue: &taskqueuepb.TaskQueue{Name: tq, Kind: enumspb.TASK_QUEUE_KIND_NORMAL},
|
|
DeploymentOptions: &deploymentpb.WorkerDeploymentOptions{
|
|
DeploymentName: deploymentName,
|
|
BuildId: testBuildID,
|
|
WorkerVersioningMode: enumspb.WORKER_VERSIONING_MODE_VERSIONED,
|
|
},
|
|
})
|
|
}()
|
|
|
|
// This needs to be done in an eventually loop since version existence in the server is eventually consistent.
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := require.New(t)
|
|
|
|
// Verify the version status is Inactive and has been registered due to a poller.
|
|
descResp, err := feClient.DescribeWorkerDeploymentVersion(ctx, &workflowservice.DescribeWorkerDeploymentVersionRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentVersion: &deploymentpb.WorkerDeploymentVersion{
|
|
DeploymentName: deploymentName,
|
|
BuildId: testBuildID,
|
|
},
|
|
})
|
|
a.NoError(err)
|
|
a.NotNil(descResp)
|
|
a.Equal(enumspb.WORKER_DEPLOYMENT_VERSION_STATUS_INACTIVE, descResp.GetWorkerDeploymentVersionInfo().GetStatus())
|
|
a.Len(descResp.GetVersionTaskQueues(), 2) // one for workflow TQ, one for activity TQ
|
|
|
|
// Promote the deployment version to either current or ramping.
|
|
err = promoteDeploymentVersion(ctx, feClient, deploymentName, testBuildID)
|
|
a.NoError(err)
|
|
|
|
// Verify the version status is the expected status.
|
|
descResp, err = feClient.DescribeWorkerDeploymentVersion(ctx, &workflowservice.DescribeWorkerDeploymentVersionRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentVersion: &deploymentpb.WorkerDeploymentVersion{
|
|
DeploymentName: deploymentName,
|
|
BuildId: testBuildID,
|
|
},
|
|
})
|
|
a.NoError(err)
|
|
a.NotNil(descResp)
|
|
a.Equal(expectedStatus, descResp.GetWorkerDeploymentVersionInfo().GetStatus())
|
|
}, 20*time.Second, 200*time.Millisecond)
|
|
|
|
// Stop the activity poller to grow the backlog and to see poller scaling decisions.
|
|
pollCancel()
|
|
|
|
// Wait for the workflow poller to poll and receive a task.
|
|
poll := <-pollResultCh
|
|
s.Require().NoError(poll.err)
|
|
s.Require().NotNil(poll.resp)
|
|
pollResp := poll.resp
|
|
|
|
// Start enough activities to ensure we will see scale up decisions. These are scheduled by an unversioned poller.
|
|
commands := make([]*commandpb.Command, 0, 10)
|
|
for i := 0; i < 10; i++ {
|
|
commands = append(commands, &commandpb.Command{
|
|
CommandType: enumspb.COMMAND_TYPE_SCHEDULE_ACTIVITY_TASK,
|
|
Attributes: &commandpb.Command_ScheduleActivityTaskCommandAttributes{ScheduleActivityTaskCommandAttributes: &commandpb.ScheduleActivityTaskCommandAttributes{
|
|
ActivityId: fmt.Sprintf("%v", i),
|
|
ActivityType: &commonpb.ActivityType{Name: "test-activity-type"},
|
|
TaskQueue: &taskqueuepb.TaskQueue{Name: tq, Kind: enumspb.TASK_QUEUE_KIND_NORMAL},
|
|
Input: payloads.EncodeString("test-input"),
|
|
StartToCloseTimeout: durationpb.New(10 * time.Second),
|
|
}},
|
|
})
|
|
}
|
|
|
|
_, err := feClient.RespondWorkflowTaskCompleted(ctx, &workflowservice.RespondWorkflowTaskCompletedRequest{
|
|
Identity: "test",
|
|
TaskToken: pollResp.TaskToken,
|
|
Commands: commands,
|
|
// Only doing this for the purpose of this test. Setting the versioning behavior to AutoUpgrade so that
|
|
// we transition the workflow to the deployment version and can poll the activities that are scheduled.
|
|
// If this was not present, all the scheduled activities would have to be dropped and we would have had to
|
|
// complete the transition task.
|
|
VersioningBehavior: enumspb.VERSIONING_BEHAVIOR_AUTO_UPGRADE,
|
|
DeploymentOptions: &deploymentpb.WorkerDeploymentOptions{
|
|
DeploymentName: deploymentName,
|
|
BuildId: testBuildID,
|
|
WorkerVersioningMode: enumspb.WORKER_VERSIONING_MODE_VERSIONED,
|
|
},
|
|
})
|
|
s.NoError(err)
|
|
|
|
// Wait to ensure add rate exceeds dispatch rate & backlog age grows.
|
|
tqtyp := enumspb.TASK_QUEUE_TYPE_ACTIVITY
|
|
s.EventuallyWithT(func(t *assert.CollectT) {
|
|
a := require.New(t)
|
|
res, err := feClient.DescribeTaskQueue(ctx, &workflowservice.DescribeTaskQueueRequest{
|
|
Namespace: s.Namespace().String(),
|
|
TaskQueue: &taskqueuepb.TaskQueue{Name: tq},
|
|
TaskQueueType: tqtyp,
|
|
ReportStats: true,
|
|
})
|
|
require.NoError(t, err)
|
|
stats := res.GetStats()
|
|
a.GreaterOrEqual(stats.ApproximateBacklogAge.AsDuration(), 200*time.Millisecond)
|
|
|
|
// Describe the deployment version to see the activity stats attributed to it.
|
|
versionDescResp, err := feClient.DescribeWorkerDeploymentVersion(ctx, &workflowservice.DescribeWorkerDeploymentVersionRequest{
|
|
Namespace: s.Namespace().String(),
|
|
DeploymentVersion: &deploymentpb.WorkerDeploymentVersion{
|
|
DeploymentName: deploymentName,
|
|
BuildId: testBuildID,
|
|
},
|
|
ReportTaskQueueStats: true,
|
|
})
|
|
a.NoError(err)
|
|
a.NotNil(versionDescResp)
|
|
|
|
found := false
|
|
for _, info := range versionDescResp.GetVersionTaskQueues() {
|
|
if info.Type == enumspb.TASK_QUEUE_TYPE_ACTIVITY {
|
|
a.Equal(int64(10), info.GetStats().GetApproximateBacklogCount())
|
|
found = true
|
|
}
|
|
}
|
|
a.True(found)
|
|
}, 20*time.Second, 200*time.Millisecond)
|
|
|
|
// Start an activity poller that's in the deployment version. This should see a scale up decision since the backlog
|
|
// is absorbed by the deployment version.
|
|
actResp, err := feClient.PollActivityTaskQueue(ctx, &workflowservice.PollActivityTaskQueueRequest{
|
|
Namespace: s.Namespace().String(),
|
|
TaskQueue: &taskqueuepb.TaskQueue{Name: tq, Kind: enumspb.TASK_QUEUE_KIND_NORMAL},
|
|
DeploymentOptions: &deploymentpb.WorkerDeploymentOptions{
|
|
DeploymentName: deploymentName,
|
|
BuildId: testBuildID,
|
|
WorkerVersioningMode: enumspb.WORKER_VERSIONING_MODE_VERSIONED,
|
|
},
|
|
})
|
|
s.NoError(err)
|
|
s.NotNil(actResp.PollerScalingDecision)
|
|
s.Equal(int32(1), actResp.PollerScalingDecision.PollRequestDeltaSuggestion)
|
|
}
|