@@ -24,13 +24,16 @@ package test_test
24
24
25
25
import (
26
26
"context"
27
+ "math"
27
28
"os"
28
29
"testing"
29
30
"time"
30
31
32
+ "github.com/stretchr/testify/assert"
31
33
"go.temporal.io/api/common/v1"
32
34
"go.temporal.io/api/serviceerror"
33
35
"go.temporal.io/api/workflowservice/v1"
36
+ "go.temporal.io/sdk/internal"
34
37
35
38
"github.com/pborman/uuid"
36
39
"github.com/stretchr/testify/require"
@@ -54,7 +57,7 @@ func TestWorkerVersioningTestSuite(t *testing.T) {
54
57
func (ts * WorkerVersioningTestSuite ) SetupSuite () {
55
58
ts .Assertions = require .New (ts .T ())
56
59
ts .workflows = & Workflows {}
57
- ts .activities = & Activities {}
60
+ ts .activities = newActivities ()
58
61
ts .NoError (ts .InitConfigAndNamespace ())
59
62
ts .NoError (ts .InitClient ())
60
63
}
@@ -800,6 +803,100 @@ func (ts *WorkerVersioningTestSuite) TestReachabilityVersionsWithRules() {
800
803
ts .Equal (client .BuildIDTaskReachability (client .BuildIDTaskReachabilityReachable ), taskQueueVersionInfo .TaskReachability )
801
804
}
802
805
806
+ func (ts * WorkerVersioningTestSuite ) TestTaskQueueStats () {
807
+ if os .Getenv ("DISABLE_BACKLOG_STATS_TESTS" ) != "" {
808
+ ts .T ().SkipNow ()
809
+ }
810
+
811
+ ctx , cancel := context .WithTimeout (context .Background (), 5 * time .Minute )
812
+ defer cancel ()
813
+
814
+ fetchAndValidateStats := func (expectedWorkflowStats * client.TaskQueueStats , expectedActivityStats * client.TaskQueueStats ) {
815
+ taskQueueInfo , err := ts .client .DescribeTaskQueueEnhanced (ctx , client.DescribeTaskQueueEnhancedOptions {
816
+ TaskQueue : ts .taskQueueName ,
817
+ TaskQueueTypes : []client.TaskQueueType {
818
+ client .TaskQueueTypeWorkflow ,
819
+ client .TaskQueueTypeActivity ,
820
+ },
821
+ ReportStats : true ,
822
+ })
823
+ ts .NoError (err )
824
+ ts .Equal (1 , len (taskQueueInfo .VersionsInfo ))
825
+
826
+ ts .validateTaskQueueStats (expectedWorkflowStats , taskQueueInfo .VersionsInfo ["" ].TypesInfo [client .TaskQueueTypeWorkflow ].Stats )
827
+ ts .validateTaskQueueStats (expectedActivityStats , taskQueueInfo .VersionsInfo ["" ].TypesInfo [client .TaskQueueTypeActivity ].Stats )
828
+ }
829
+
830
+ // Basic workflow runs two activities
831
+ handle , err := ts .client .ExecuteWorkflow (ctx , ts .startWorkflowOptions ("basic-wf" ), ts .workflows .Basic )
832
+ ts .NoError (err )
833
+
834
+ // Wait until the task goes to the TQ
835
+ ts .EventuallyWithT (
836
+ func (t * assert.CollectT ) {
837
+ taskQueueInfo , err := ts .client .DescribeTaskQueueEnhanced (ctx , client.DescribeTaskQueueEnhancedOptions {
838
+ TaskQueue : ts .taskQueueName ,
839
+ TaskQueueTypes : []client.TaskQueueType {
840
+ client .TaskQueueTypeWorkflow ,
841
+ },
842
+ ReportStats : true ,
843
+ })
844
+ ts .NoError (err )
845
+ ts .Equal (1 , len (taskQueueInfo .VersionsInfo ))
846
+ ts .NotNil (taskQueueInfo .VersionsInfo ["" ].TypesInfo [client .TaskQueueTypeWorkflow ])
847
+ ts .NotNil (taskQueueInfo .VersionsInfo ["" ].TypesInfo [client .TaskQueueTypeWorkflow ].Stats )
848
+ assert .Greater (t , taskQueueInfo .VersionsInfo ["" ].TypesInfo [client .TaskQueueTypeWorkflow ].Stats .ApproximateBacklogCount , int64 (0 ))
849
+ },
850
+ time .Second , 100 * time .Millisecond ,
851
+ )
852
+
853
+ // no workers yet, so only workflow should have a backlog
854
+ fetchAndValidateStats (
855
+ & client.TaskQueueStats {
856
+ ApproximateBacklogCount : 1 ,
857
+ ApproximateBacklogAge : time .Millisecond ,
858
+ BacklogIncreaseRate : 1 ,
859
+ TasksAddRate : 1 ,
860
+ TasksDispatchRate : 0 ,
861
+ },
862
+ & client.TaskQueueStats {
863
+ ApproximateBacklogCount : 0 ,
864
+ ApproximateBacklogAge : 0 ,
865
+ BacklogIncreaseRate : 0 ,
866
+ TasksAddRate : 0 ,
867
+ TasksDispatchRate : 0 ,
868
+ },
869
+ )
870
+
871
+ // run the worker
872
+ worker1 := worker .New (ts .client , ts .taskQueueName , worker.Options {DisableEagerActivities : true })
873
+ ts .workflows .register (worker1 )
874
+ ts .activities .register (worker1 )
875
+ ts .NoError (worker1 .Start ())
876
+ defer worker1 .Stop ()
877
+
878
+ // Wait for the wf to finish
879
+ ts .NoError (handle .Get (ctx , nil ))
880
+
881
+ // backlogs should be empty but the rates should be non-zero
882
+ fetchAndValidateStats (
883
+ & client.TaskQueueStats {
884
+ ApproximateBacklogCount : 0 ,
885
+ ApproximateBacklogAge : 0 ,
886
+ BacklogIncreaseRate : 0 ,
887
+ TasksAddRate : 1 ,
888
+ TasksDispatchRate : 1 ,
889
+ },
890
+ & client.TaskQueueStats {
891
+ ApproximateBacklogCount : 0 ,
892
+ ApproximateBacklogAge : 0 ,
893
+ BacklogIncreaseRate : 0 ,
894
+ TasksAddRate : 1 ,
895
+ TasksDispatchRate : 1 ,
896
+ },
897
+ )
898
+ }
899
+
803
900
func (ts * WorkerVersioningTestSuite ) TestBuildIDChangesOverWorkflowLifetime () {
804
901
// TODO: Unskip this test, it is flaky with server 1.25.0-rc.0
805
902
if os .Getenv ("DISABLE_SERVER_1_25_TESTS" ) != "" {
@@ -984,3 +1081,38 @@ func (ts *WorkerVersioningTestSuite) TestBuildIDChangesOverWorkflowLifetimeWithR
984
1081
ts .NoError (enval .Get (& lastBuildID ))
985
1082
ts .Equal ("1.1" , lastBuildID )
986
1083
}
1084
+
1085
+ // validateTaskQueueStats compares expected vs actual stats.
1086
+ // For age and rates, it treats all non-zero values the same.
1087
+ // For BacklogIncreaseRate for non-zero expected values we only compare the sign (i.e. backlog grows or shrinks), while
1088
+ // zero expected value means "not specified".
1089
+ func (ts * WorkerVersioningTestSuite ) validateTaskQueueStats (expected * client.TaskQueueStats , actual * internal.TaskQueueStats ) {
1090
+ if expected == nil {
1091
+ ts .Nil (actual )
1092
+ return
1093
+ }
1094
+ ts .NotNil (actual )
1095
+ ts .Equal (expected .ApproximateBacklogCount , actual .ApproximateBacklogCount )
1096
+ if expected .ApproximateBacklogAge == 0 {
1097
+ ts .Equal (time .Duration (0 ), actual .ApproximateBacklogAge )
1098
+ } else {
1099
+ ts .Greater (actual .ApproximateBacklogAge , time .Duration (0 ))
1100
+ }
1101
+ if expected .TasksAddRate == 0 {
1102
+ // TODO: do not accept NaN once the server code is fixed: https://github.com/temporalio/temporal/pull/6404
1103
+ ts .True (float32 (0 ) == actual .TasksAddRate || math .IsNaN (float64 (actual .TasksAddRate )))
1104
+ } else {
1105
+ ts .Greater (actual .TasksAddRate , float32 (0 ))
1106
+ }
1107
+ if expected .TasksDispatchRate == 0 {
1108
+ // TODO: do not accept NaN once the server code is fixed: https://github.com/temporalio/temporal/pull/6404
1109
+ ts .True (float32 (0 ) == actual .TasksDispatchRate || math .IsNaN (float64 (actual .TasksDispatchRate )))
1110
+ } else {
1111
+ ts .Greater (actual .TasksDispatchRate , float32 (0 ))
1112
+ }
1113
+ if expected .BacklogIncreaseRate > 0 {
1114
+ ts .Greater (actual .BacklogIncreaseRate , float32 (0 ))
1115
+ } else if expected .BacklogIncreaseRate < 0 {
1116
+ ts .Less (actual .BacklogIncreaseRate , float32 (0 ))
1117
+ }
1118
+ }
0 commit comments