diff --git a/cliext/client.go b/cliext/client.go index db6506078..d40010db1 100644 --- a/cliext/client.go +++ b/cliext/client.go @@ -200,6 +200,10 @@ func (b *ClientOptionsBuilder) Build(ctx context.Context) (client.Options, error return client.Options{}, fmt.Errorf("failed to build client options: %w", err) } + if profile.TLS != nil && profile.TLS.Disabled { + clientOpts.ConnectionOptions.TLSDisabled = true + } + // Set client authority if provided. if cfg.ClientAuthority != "" { clientOpts.ConnectionOptions.Authority = cfg.ClientAuthority diff --git a/cliext/go.mod b/cliext/go.mod index f58a46c68..acd30cc4b 100644 --- a/cliext/go.mod +++ b/cliext/go.mod @@ -7,10 +7,10 @@ require ( github.com/mattn/go-isatty v0.0.20 github.com/spf13/pflag v1.0.10 github.com/stretchr/testify v1.10.0 - go.temporal.io/sdk v1.32.1 + go.temporal.io/sdk v1.40.0 go.temporal.io/sdk/contrib/envconfig v0.1.0 golang.org/x/oauth2 v0.33.0 - google.golang.org/grpc v1.66.0 + google.golang.org/grpc v1.67.1 ) require ( @@ -19,22 +19,20 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/mock v1.6.0 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 // indirect + github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 // indirect github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 // indirect - github.com/nexus-rpc/sdk-go v0.3.0 // indirect - github.com/pborman/uuid v1.2.1 // indirect + github.com/nexus-rpc/sdk-go v0.5.1 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/robfig/cron v1.2.0 // indirect github.com/stretchr/objx v0.5.2 // indirect - go.temporal.io/api v1.44.1 // indirect - golang.org/x/exp v0.0.0-20231127185646-65229373498e // indirect - golang.org/x/net v0.38.0 // indirect - golang.org/x/sync v0.12.0 // indirect - golang.org/x/sys v0.31.0 // indirect - golang.org/x/text v0.23.0 // indirect + go.temporal.io/api v1.62.1 // indirect + golang.org/x/net v0.39.0 // indirect + golang.org/x/sync v0.13.0 // indirect + golang.org/x/sys v0.32.0 // indirect + golang.org/x/text v0.24.0 // indirect golang.org/x/time v0.3.0 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed // indirect google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed // indirect - google.golang.org/protobuf v1.34.2 // indirect + google.golang.org/protobuf v1.36.6 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/cliext/go.sum b/cliext/go.sum index ab0d09f66..db6f12144 100644 --- a/cliext/go.sum +++ b/cliext/go.sum @@ -1,155 +1,90 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v1.4.0 h1:kuoIxZQy2WRRk1pttg9asf+WVv6tWQuBNVmK8+nqPr0= github.com/BurntSushi/toml v1.4.0/go.mod h1:ukJfTF/6rtPPRCnwkur4qwRxa8vTRFBF0uk2lLoLwho= -github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= -github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= -github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= -github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a h1:yDWHCSQ40h88yih2JAcL6Ls/kVkSE8GFACTGVnMPruw= github.com/facebookgo/clock v0.0.0-20150410010913-600d898af40a/go.mod h1:7Ga40egUymuWXxAe151lTNnCv97MddSOVsjpPPkityA= -github.com/go-kit/log v0.1.0/go.mod h1:zbhenjAZHb184qTLMA9ZjW7ThYL0H2mk7Q6pNt4vbaY= -github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q= github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.6.0 h1:ErTB+efbowRARo13NNdxyJji2egdxLGQhRaY+DUumQc= github.com/golang/mock v1.6.0/go.mod h1:p6yTPP+5HYm5mzsMV8JkE6ZKdX+/wYM6Hr+LicevLPs= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw= -github.com/golang/protobuf v1.5.0 h1:LUVKkCeviFUMKqHa4tXIIij/lbhnMbP7Fn5wKdKkRh4= -github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/uuid v1.0.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/grpc-ecosystem/go-grpc-middleware v1.4.0 h1:UH//fgunKIs4JdUbpDl1VZCDaL56wXCB/5+wF6uHfaI= -github.com/grpc-ecosystem/go-grpc-middleware v1.4.0/go.mod h1:g5qyo/la0ALbONm6Vbp88Yd8NsDy6rZz+RcrMPxvld8= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2 h1:sGm2vDRFUrQJO/Veii4h4zG2vvqG6uWNkBHSTqXOZk0= +github.com/grpc-ecosystem/go-grpc-middleware/v2 v2.3.2/go.mod h1:wd1YpapPLivG6nQgbf7ZkG1hhSOXDhhn4MLTknx2aAc= github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0 h1:asbCHRVmodnJTuQ3qamDwqVOIjwqUPTYmYuemVOx+Ys= github.com/grpc-ecosystem/grpc-gateway/v2 v2.22.0/go.mod h1:ggCgvZ2r7uOoQjOyu2Y1NhHmEPPzzuhWgcza5M1Ji1I= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= -github.com/nexus-rpc/sdk-go v0.3.0 h1:Y3B0kLYbMhd4C2u00kcYajvmOrfozEtTV/nHSnV57jA= -github.com/nexus-rpc/sdk-go v0.3.0/go.mod h1:TpfkM2Cw0Rlk9drGkoiSMpFqflKTiQLWUNyKJjF8mKQ= -github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= -github.com/pborman/uuid v1.2.1 h1:+ZZIw58t/ozdjRaXh/3awHfmWRbzYxJoAdNJxe/3pvw= -github.com/pborman/uuid v1.2.1/go.mod h1:X/NO0urCmaxf9VXbdlT7C2Yzkj2IKimNn4k+gtPdI/k= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/nexus-rpc/sdk-go v0.5.1 h1:UFYYfoHlQc+Pn9gQpmn9QE7xluewAn2AO1OSkAh7YFU= +github.com/nexus-rpc/sdk-go v0.5.1/go.mod h1:FHdPfVQwRuJFZFTF0Y2GOAxCrbIBNrcPna9slkGKPYk= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= github.com/robfig/cron v1.2.0 h1:ZjScXvvxeQ63Dbyxy76Fj3AT3Ut0aKsyd2/tl3DTMuQ= github.com/robfig/cron v1.2.0/go.mod h1:JGuDeoQd7Z6yL4zQhZ3OPEVHB7fL6Ka6skscFHfmt2k= github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M= github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA= -github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY= github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -go.temporal.io/api v1.44.1 h1:sb5Hq08AB0WtYvfLJMiWmHzxjqs2b+6Jmzg4c8IOeng= -go.temporal.io/api v1.44.1/go.mod h1:1WwYUMo6lao8yl0371xWUm13paHExN5ATYT/B7QtFis= -go.temporal.io/sdk v1.32.1 h1:slA8prhdFr4lxpsTcRusWVitD/cGjELfKUh0mBj73SU= -go.temporal.io/sdk v1.32.1/go.mod h1:8U8H7rF9u4Hyb4Ry9yiEls5716DHPNvVITPNkgWUwE8= +go.temporal.io/api v1.62.1 h1:7UHMNOIqfYBVTaW0JIh/wDpw2jORkB6zUKsxGtvjSZU= +go.temporal.io/api v1.62.1/go.mod h1:iaxoP/9OXMJcQkETTECfwYq4cw/bj4nwov8b3ZLVnXM= +go.temporal.io/sdk v1.40.0 h1:n9JN3ezVpWBxLzz5xViCo0sKxp7kVVhr1Su0bcMRNNs= +go.temporal.io/sdk v1.40.0/go.mod h1:tauxVfN174F0bdEs27+i0h8UPD7xBb6Py2SPHo7f1C0= go.temporal.io/sdk/contrib/envconfig v0.1.0 h1:s+G/Ujph+Xl2jzLiiIm2T1vuijDkUL4Kse49dgDVGBE= go.temporal.io/sdk/contrib/envconfig v0.1.0/go.mod h1:FQEO3C56h9C7M6sDgSanB8HnBTmopw9qgVx4F1S6pJk= -go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= -go.uber.org/goleak v1.1.10/go.mod h1:8a7PlsEVH3e/a/GLqe5IIrQx6GzcnRmZEufDUTk4A7A= -go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU= -go.uber.org/zap v1.18.1/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/exp v0.0.0-20231127185646-65229373498e h1:Gvh4YaCaXNs6dKTlfgismwWZKyjVZXwOPfIyUaqU3No= -golang.org/x/exp v0.0.0-20231127185646-65229373498e/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= -golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= -golang.org/x/net v0.38.0 h1:vRMAPTMaeGqVhG5QyLJHqNDwecKTomGeqbnfZyKlBI8= -golang.org/x/net v0.38.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/net v0.39.0 h1:ZCu7HMWDxpXpaiKdhzIfaltL9Lp31x/3fCP11bc6/fY= +golang.org/x/net v0.39.0/go.mod h1:X7NRbYVEA+ewNkCNyJ513WmMdQ3BineSwVtN2zD/d+E= golang.org/x/oauth2 v0.33.0 h1:4Q+qn+E5z8gPRJfmRy7C2gGG3T4jIprK6aSYgTXGRpo= golang.org/x/oauth2 v0.33.0/go.mod h1:lzm5WQJQwKZ3nwavOZ3IS5Aulzxi68dUSgRHujetwEA= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.12.0 h1:MHc5BpPuC30uJk597Ri8TV3CNZcTLu6B6z4lJy+g6Jw= -golang.org/x/sync v0.12.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= +golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik= -golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= +golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= +golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/text v0.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY= -golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4= +golang.org/x/text v0.24.0 h1:dd5Bzh4yt5KYA8f9CJHCP4FB4D51c2c6JvN37xJJkJ0= +golang.org/x/text v0.24.0/go.mod h1:L8rBsPeo2pSS+xqN0d5u2ikmjtmoJbDBT1b7nHvFCdU= golang.org/x/time v0.3.0 h1:rg5rLMjNzMS1RkNLzCG38eapWhnYLFYXDXj2gOlr8j4= golang.org/x/time v0.3.0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= -golang.org/x/tools v0.0.0-20191108193012-7d206e10da11/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE= golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA= @@ -158,33 +93,16 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= -google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c= google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed h1:3RgNmBoI9MZhsj3QxC+AP/qQhNwpCLOvYDYYsFrhFt0= google.golang.org/genproto/googleapis/api v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:OCdP9MfskevB/rbYvHTsXTtKC+3bHWajPdoKgjcYkfo= google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed h1:J6izYgfBXAI3xTKLgxzTmUltdYaLsuBxFCgDHWJ/eXg= google.golang.org/genproto/googleapis/rpc v0.0.0-20240827150818-7e3bb234dfed/go.mod h1:UqMtugtsSgubUsoxbuAoiCXvqvErP7Gf0so0mK9tHxU= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= -google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY= -google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= -google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk= -google.golang.org/grpc v1.66.0 h1:DibZuoBznOxbDQxRINckZcUvnCEvrW9pcWIE2yF9r1c= -google.golang.org/grpc v1.66.0/go.mod h1:s3/l6xSSCURdVfAnL+TqCNMyTDAGN6+lZeVxnZR128Y= -google.golang.org/protobuf v1.34.2 h1:6xV6lTsCfpGD21XK49h7MhtcApnLqkfYgPcdHftf6hg= -google.golang.org/protobuf v1.34.2/go.mod h1:qYOHts0dSfpeUzUFpOMr/WGzszTmLH+DiWniOlNbLDw= +google.golang.org/grpc v1.67.1 h1:zWnc1Vrcno+lHZCOofnIMvycFcc0QRGIzm9dhnDX68E= +google.golang.org/grpc v1.67.1/go.mod h1:1gLDyUQU7CTLJI90u3nXZ9ekeghjeM7pTDZlqFNg2AA= +google.golang.org/protobuf v1.36.6 h1:z1NpPI8ku2WgiWnf+t9wTPsn6eP1L7ksHUlkfLvd9xY= +google.golang.org/protobuf v1.36.6/go.mod h1:jduwjTPXsFjZGTmRluh+L6NjiWu7pchiJ2/5YcXBHnY= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= diff --git a/go.mod b/go.mod index a7be6a19f..fe89664c0 100644 --- a/go.mod +++ b/go.mod @@ -10,24 +10,24 @@ require ( github.com/fatih/color v1.18.0 github.com/google/uuid v1.6.0 github.com/mattn/go-isatty v0.0.20 - github.com/nexus-rpc/sdk-go v0.5.1 + github.com/nexus-rpc/sdk-go v0.5.2-0.20260211051645-26b0b4c584e5 github.com/olekukonko/tablewriter v0.0.5 github.com/spf13/cobra v1.10.2 github.com/spf13/pflag v1.0.10 github.com/stretchr/testify v1.10.0 github.com/temporalio/cli/cliext v0.0.0 github.com/temporalio/ui-server/v2 v2.45.3 - go.temporal.io/api v1.60.2 - go.temporal.io/sdk v1.38.0 + go.temporal.io/api v1.62.2 + go.temporal.io/sdk v1.40.0 go.temporal.io/sdk/contrib/envconfig v0.1.0 - go.temporal.io/server v1.30.0 + go.temporal.io/server v1.31.0-151.2 golang.org/x/mod v0.31.0 golang.org/x/term v0.38.0 golang.org/x/tools v0.40.0 google.golang.org/grpc v1.72.2 google.golang.org/protobuf v1.36.6 gopkg.in/yaml.v3 v3.0.1 - modernc.org/sqlite v1.39.1 + modernc.org/sqlite v1.44.3 ) replace github.com/temporalio/cli/cliext => ./cliext @@ -105,7 +105,7 @@ require ( github.com/mitchellh/mapstructure v1.5.0 // indirect github.com/mitchellh/reflectwalk v1.0.2 // indirect github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect - github.com/ncruces/go-strftime v0.1.9 // indirect + github.com/ncruces/go-strftime v1.0.0 // indirect github.com/olivere/elastic/v7 v7.0.32 // indirect github.com/opentracing/opentracing-go v1.2.0 // indirect github.com/pkg/errors v0.9.1 // indirect @@ -129,6 +129,7 @@ require ( github.com/temporalio/ringpop-go v0.0.0-20250130211428-b97329e994f7 // indirect github.com/temporalio/sqlparser v0.0.0-20231115171017-f4060bcfa6cb // indirect github.com/temporalio/tchannel-go v1.22.1-0.20240528171429-1db37fdea938 // indirect + github.com/tidwall/btree v1.8.1 // indirect github.com/twmb/murmur3 v1.1.8 // indirect github.com/uber-common/bark v1.3.0 // indirect github.com/uber-go/tally/v4 v4.1.17 // indirect @@ -156,7 +157,7 @@ require ( go.uber.org/multierr v1.11.0 // indirect go.uber.org/zap v1.27.0 // indirect golang.org/x/crypto v0.46.0 // indirect - golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b // indirect + golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect golang.org/x/net v0.48.0 // indirect golang.org/x/oauth2 v0.33.0 // indirect golang.org/x/sync v0.19.0 // indirect @@ -169,7 +170,7 @@ require ( google.golang.org/genproto/googleapis/rpc v0.0.0-20250324211829-b45e905df463 // indirect gopkg.in/inf.v0 v0.9.1 // indirect gopkg.in/validator.v2 v2.0.1 // indirect - modernc.org/libc v1.66.10 // indirect + modernc.org/libc v1.67.6 // indirect modernc.org/mathutil v1.7.1 // indirect modernc.org/memory v1.11.0 // indirect ) diff --git a/go.sum b/go.sum index 5023ba7c9..c6264a87f 100644 --- a/go.sum +++ b/go.sum @@ -170,6 +170,8 @@ github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5uk github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed h1:5upAirOpQc1Q53c0bnx2ufif5kANL7bfZWcc6VJWJd8= github.com/hailocab/go-hostpool v0.0.0-20160125115350-e80d13ce29ed/go.mod h1:tMWxXQ9wFIaZeTI9F+hmhFiGpFmhOHzyShyFUhRm0H4= +github.com/hashicorp/golang-lru/v2 v2.0.7 h1:a+bsQ5rvGLjzHuww6tVxozPZFVghXaHOwFs4luLUK2k= +github.com/hashicorp/golang-lru/v2 v2.0.7/go.mod h1:QeFd9opnmA6QUJc5vARoKUSoFhyfM2/ZepoAG6RGpeM= github.com/huandu/xstrings v1.5.0 h1:2ag3IFq9ZDANvthTwTiqSSZLjDc+BedvHPAp5tJy2TI= github.com/huandu/xstrings v1.5.0/go.mod h1:y5/lhBue+AyNmUVz9RLU9xbLR0o4KIIExikq4ovT0aE= github.com/iancoleman/strcase v0.3.0 h1:nTXanmYxhfFAMjZL34Ov6gkzEsSJZ5DbhxWjvSASxEI= @@ -241,10 +243,10 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/ncruces/go-strftime v0.1.9 h1:bY0MQC28UADQmHmaF5dgpLmImcShSi2kHU9XLdhx/f4= -github.com/ncruces/go-strftime v0.1.9/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= -github.com/nexus-rpc/sdk-go v0.5.1 h1:UFYYfoHlQc+Pn9gQpmn9QE7xluewAn2AO1OSkAh7YFU= -github.com/nexus-rpc/sdk-go v0.5.1/go.mod h1:FHdPfVQwRuJFZFTF0Y2GOAxCrbIBNrcPna9slkGKPYk= +github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w= +github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls= +github.com/nexus-rpc/sdk-go v0.5.2-0.20260211051645-26b0b4c584e5 h1:Van9KGGs8lcDgxzSNFbDhEMNeJ80TbBxwZ45f9iBk9U= +github.com/nexus-rpc/sdk-go v0.5.2-0.20260211051645-26b0b4c584e5/go.mod h1:FHdPfVQwRuJFZFTF0Y2GOAxCrbIBNrcPna9slkGKPYk= github.com/niemeyer/pretty v0.0.0-20200227124842-a10e7caefd8e/go.mod h1:zD1mROLANZcx1PVRCS0qkT7pwLkGfwJo4zjcN/Tysno= github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec= github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY= @@ -325,6 +327,8 @@ github.com/temporalio/tchannel-go v1.22.1-0.20240528171429-1db37fdea938 h1:sEJGh github.com/temporalio/tchannel-go v1.22.1-0.20240528171429-1db37fdea938/go.mod h1:ezRQRwu9KQXy8Wuuv1aaFFxoCNz5CeNbVOOkh3xctbY= github.com/temporalio/ui-server/v2 v2.45.3 h1:htzeDjUq77Il8bjFuel2bHFC3tA6SNx6clU2iQS0RRI= github.com/temporalio/ui-server/v2 v2.45.3/go.mod h1:tsl7cOECAi/uCnCpdMZ//F2Fi8RWTPAvFdRlz3qk19U= +github.com/tidwall/btree v1.8.1 h1:27ehoXvm5AG/g+1VxLS1SD3vRhp/H7LuEfwNvddEdmA= +github.com/tidwall/btree v1.8.1/go.mod h1:jBbTdUWhSZClZWoDg54VnvV7/54modSOzDN7VXftj1A= github.com/twmb/murmur3 v1.1.8 h1:8Yt9taO/WN3l08xErzjeschgZU2QSrwm1kclYq+0aRg= github.com/twmb/murmur3 v1.1.8/go.mod h1:Qq/R7NUyOfr65zD+6Q5IHKsJLwP7exErjN6lyyq3OSQ= github.com/uber-common/bark v1.0.0/go.mod h1:g0ZuPcD7XiExKHynr93Q742G/sbrdVQkghrqLGOoFuY= @@ -379,14 +383,14 @@ go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc= go.opentelemetry.io/proto/otlp v1.5.0 h1:xJvq7gMzB31/d406fB8U5CBdyQGw4P399D1aQWU/3i4= go.opentelemetry.io/proto/otlp v1.5.0/go.mod h1:keN8WnHxOy8PG0rQZjJJ5A2ebUoafqWp0eVQ4yIXvJ4= -go.temporal.io/api v1.60.2 h1:xqUqdPeOu8/HNWVPu51P6tVoBJ5kRh8nBI62xXi+IWg= -go.temporal.io/api v1.60.2/go.mod h1:iaxoP/9OXMJcQkETTECfwYq4cw/bj4nwov8b3ZLVnXM= -go.temporal.io/sdk v1.38.0 h1:4Bok5LEdED7YKpsSjIa3dDqram5VOq+ydBf4pyx0Wo4= -go.temporal.io/sdk v1.38.0/go.mod h1:a+R2Ej28ObvHoILbHaxMyind7M6D+W0L7edt5UJF4SE= +go.temporal.io/api v1.62.2 h1:jFhIzlqNyJsJZTiCRQmTIMv6OTQ5BZ57z8gbgLGMaoo= +go.temporal.io/api v1.62.2/go.mod h1:iaxoP/9OXMJcQkETTECfwYq4cw/bj4nwov8b3ZLVnXM= +go.temporal.io/sdk v1.40.0 h1:n9JN3ezVpWBxLzz5xViCo0sKxp7kVVhr1Su0bcMRNNs= +go.temporal.io/sdk v1.40.0/go.mod h1:tauxVfN174F0bdEs27+i0h8UPD7xBb6Py2SPHo7f1C0= go.temporal.io/sdk/contrib/envconfig v0.1.0 h1:s+G/Ujph+Xl2jzLiiIm2T1vuijDkUL4Kse49dgDVGBE= go.temporal.io/sdk/contrib/envconfig v0.1.0/go.mod h1:FQEO3C56h9C7M6sDgSanB8HnBTmopw9qgVx4F1S6pJk= -go.temporal.io/server v1.30.0 h1:g6JStvvmh4qhPhZ94lPipms7hwGLs4IB63a2PcIOC3M= -go.temporal.io/server v1.30.0/go.mod h1:tERB4Wh+w/LFgJqe0flHEkAuYOLEXkE/J6e2fiQOTaI= +go.temporal.io/server v1.31.0-151.2 h1:PNik+0rEs8naYOtXshjq1jttriCN6/AUvkp3xJeUiAY= +go.temporal.io/server v1.31.0-151.2/go.mod h1:to4xxRN2mhT7DLvn4TXCJ5V2WGNHfgtypwE6gpie818= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc= go.uber.org/atomic v1.11.0 h1:ZvwS0R+56ePWxUNi+Atn9dWONBPp/AUETXlHW0DxSjE= @@ -421,8 +425,8 @@ golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= -golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b h1:M2rDM6z3Fhozi9O7NWsxAkg/yqS/lQJ6PmkyIV3YP+o= -golang.org/x/exp v0.0.0-20250620022241-b7579e27df2b/go.mod h1:3//PLf8L/X+8b4vuAfHzxeRUl04Adcb341+IGKfnqS8= +golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2wtOnGAHZWCHUM4KGzY= +golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70= golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= @@ -553,18 +557,20 @@ gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= -modernc.org/cc/v4 v4.26.5 h1:xM3bX7Mve6G8K8b+T11ReenJOT+BmVqQj0FY5T4+5Y4= -modernc.org/cc/v4 v4.26.5/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= -modernc.org/ccgo/v4 v4.28.1 h1:wPKYn5EC/mYTqBO373jKjvX2n+3+aK7+sICCv4Fjy1A= -modernc.org/ccgo/v4 v4.28.1/go.mod h1:uD+4RnfrVgE6ec9NGguUNdhqzNIeeomeXf6CL0GTE5Q= +modernc.org/cc/v4 v4.27.1 h1:9W30zRlYrefrDV2JE2O8VDtJ1yPGownxciz5rrbQZis= +modernc.org/cc/v4 v4.27.1/go.mod h1:uVtb5OGqUKpoLWhqwNQo/8LwvoiEBLvZXIQ/SmO6mL0= +modernc.org/ccgo/v4 v4.30.1 h1:4r4U1J6Fhj98NKfSjnPUN7Ze2c6MnAdL0hWw6+LrJpc= +modernc.org/ccgo/v4 v4.30.1/go.mod h1:bIOeI1JL54Utlxn+LwrFyjCx2n2RDiYEaJVSrgdrRfM= modernc.org/fileutil v1.3.40 h1:ZGMswMNc9JOCrcrakF1HrvmergNLAmxOPjizirpfqBA= modernc.org/fileutil v1.3.40/go.mod h1:HxmghZSZVAz/LXcMNwZPA/DRrQZEVP9VX0V4LQGQFOc= modernc.org/gc/v2 v2.6.5 h1:nyqdV8q46KvTpZlsw66kWqwXRHdjIlJOhG6kxiV/9xI= modernc.org/gc/v2 v2.6.5/go.mod h1:YgIahr1ypgfe7chRuJi2gD7DBQiKSLMPgBQe9oIiito= +modernc.org/gc/v3 v3.1.1 h1:k8T3gkXWY9sEiytKhcgyiZ2L0DTyCQ/nvX+LoCljoRE= +modernc.org/gc/v3 v3.1.1/go.mod h1:HFK/6AGESC7Ex+EZJhJ2Gni6cTaYpSMmU/cT9RmlfYY= modernc.org/goabi0 v0.2.0 h1:HvEowk7LxcPd0eq6mVOAEMai46V+i7Jrj13t4AzuNks= modernc.org/goabi0 v0.2.0/go.mod h1:CEFRnnJhKvWT1c1JTI3Avm+tgOWbkOu5oPA8eH8LnMI= -modernc.org/libc v1.66.10 h1:yZkb3YeLx4oynyR+iUsXsybsX4Ubx7MQlSYEw4yj59A= -modernc.org/libc v1.66.10/go.mod h1:8vGSEwvoUoltr4dlywvHqjtAqHBaw0j1jI7iFBTAr2I= +modernc.org/libc v1.67.6 h1:eVOQvpModVLKOdT+LvBPjdQqfrZq+pC39BygcT+E7OI= +modernc.org/libc v1.67.6/go.mod h1:JAhxUVlolfYDErnwiqaLvUqc8nfb2r6S6slAgZOnaiE= modernc.org/mathutil v1.7.1 h1:GCZVGXdaN8gTqB1Mf/usp1Y/hSqgI2vAGGP4jZMCxOU= modernc.org/mathutil v1.7.1/go.mod h1:4p5IwJITfppl0G4sUEDtCr4DthTaT47/N3aT6MhfgJg= modernc.org/memory v1.11.0 h1:o4QC8aMQzmcwCK3t3Ux/ZHmwFPzE6hf2Y5LbkRs+hbI= @@ -573,8 +579,8 @@ modernc.org/opt v0.1.4 h1:2kNGMRiUjrp4LcaPuLY2PzUfqM/w9N23quVwhKt5Qm8= modernc.org/opt v0.1.4/go.mod h1:03fq9lsNfvkYSfxrfUhZCWPk1lm4cq4N+Bh//bEtgns= modernc.org/sortutil v1.2.1 h1:+xyoGf15mM3NMlPDnFqrteY07klSFxLElE2PVuWIJ7w= modernc.org/sortutil v1.2.1/go.mod h1:7ZI3a3REbai7gzCLcotuw9AC4VZVpYMjDzETGsSMqJE= -modernc.org/sqlite v1.39.1 h1:H+/wGFzuSCIEVCvXYVHX5RQglwhMOvtHSv+VtidL2r4= -modernc.org/sqlite v1.39.1/go.mod h1:9fjQZ0mB1LLP0GYrp39oOJXx/I2sxEnZtzCmEQIKvGE= +modernc.org/sqlite v1.44.3 h1:+39JvV/HWMcYslAwRxHb8067w+2zowvFOUrOWIy9PjY= +modernc.org/sqlite v1.44.3/go.mod h1:CzbrU2lSB1DKUusvwGz7rqEKIq+NUd8GWuBBZDs9/nA= modernc.org/strutil v1.2.1 h1:UneZBkQA+DX2Rp35KcM69cSsNES9ly8mQWD71HKlOA0= modernc.org/strutil v1.2.1/go.mod h1:EHkiggD70koQxjVdSBM3JKM7k6L0FbGE5eymy9i3B9A= modernc.org/token v1.1.0 h1:Xl7Ap9dKaEs5kLoOQeQmPWevfnk/DM5qcLcYlA8ys6Y= diff --git a/internal/temporalcli/commands.activity.go b/internal/temporalcli/commands.activity.go index bff15f986..e761e14b2 100644 --- a/internal/temporalcli/commands.activity.go +++ b/internal/temporalcli/commands.activity.go @@ -1,16 +1,25 @@ package temporalcli import ( + "context" + "encoding/json" + "errors" "fmt" "time" + "github.com/fatih/color" "github.com/temporalio/cli/internal/printer" activitypb "go.temporal.io/api/activity/v1" "go.temporal.io/api/batch/v1" "go.temporal.io/api/common/v1" + enumspb "go.temporal.io/api/enums/v1" "go.temporal.io/api/failure/v1" + "go.temporal.io/api/serviceerror" taskqueuepb "go.temporal.io/api/taskqueue/v1" "go.temporal.io/api/workflowservice/v1" + "go.temporal.io/sdk/client" + "go.temporal.io/sdk/converter" + "go.temporal.io/sdk/temporal" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/fieldmaskpb" ) @@ -31,6 +40,538 @@ type ( } ) +func (c *TemporalActivityStartCommand) run(cctx *CommandContext, args []string) error { + cl, err := dialClient(cctx, &c.Parent.ClientOptions) + if err != nil { + return err + } + defer cl.Close() + + handle, err := startActivity(cctx, cl, &c.ActivityStartOptions, &c.PayloadInputOptions) + if err != nil { + return err + } + return printActivityExecution(cctx, c.ActivityId, handle.GetRunID(), c.Type, c.Parent.Namespace, c.TaskQueue) +} + +func (c *TemporalActivityExecuteCommand) run(cctx *CommandContext, args []string) error { + cl, err := dialClient(cctx, &c.Parent.ClientOptions) + if err != nil { + return err + } + defer cl.Close() + + handle, err := startActivity(cctx, cl, &c.ActivityStartOptions, &c.PayloadInputOptions) + if err != nil { + return err + } + if !cctx.JSONOutput { + if err := printActivityExecution(cctx, c.ActivityId, handle.GetRunID(), c.Type, c.Parent.Namespace, c.TaskQueue); err != nil { + cctx.Logger.Error("Failed printing execution info", "error", err) + } + } + return getActivityResult(cctx, cl, c.Parent.Namespace, c.ActivityId, handle.GetRunID()) +} + +func (c *TemporalActivityResultCommand) run(cctx *CommandContext, args []string) error { + cl, err := dialClient(cctx, &c.Parent.ClientOptions) + if err != nil { + return err + } + defer cl.Close() + + return getActivityResult(cctx, cl, c.Parent.Namespace, c.ActivityId, c.RunId) +} + +func startActivity( + cctx *CommandContext, + cl client.Client, + opts *ActivityStartOptions, + inputOpts *PayloadInputOptions, +) (client.ActivityHandle, error) { + startOpts, err := buildStartActivityOptions(opts) + if err != nil { + return nil, err + } + input, err := inputOpts.buildRawInput() + if err != nil { + return nil, err + } + cctx.Context, err = contextWithHeaders(cctx.Context, opts.Headers) + if err != nil { + return nil, err + } + handle, err := cl.ExecuteActivity(cctx, startOpts, opts.Type, input...) + if err != nil { + return nil, fmt.Errorf("failed starting activity: %w", err) + } + return handle, nil +} + +func printActivityExecution(cctx *CommandContext, activityID, runID, activityType, namespace, taskQueue string) error { + if !cctx.JSONOutput { + cctx.Printer.Println(color.MagentaString("Running execution:")) + } + return cctx.Printer.PrintStructured(struct { + ActivityId string `json:"activityId"` + RunId string `json:"runId"` + Type string `json:"type"` + Namespace string `json:"namespace"` + TaskQueue string `json:"taskQueue"` + }{ + ActivityId: activityID, + RunId: runID, + Type: activityType, + Namespace: namespace, + TaskQueue: taskQueue, + }, printer.StructuredOptions{}) +} + +func buildStartActivityOptions(opts *ActivityStartOptions) (client.StartActivityOptions, error) { + o := client.StartActivityOptions{ + ID: opts.ActivityId, + TaskQueue: opts.TaskQueue, + ScheduleToCloseTimeout: opts.ScheduleToCloseTimeout.Duration(), + ScheduleToStartTimeout: opts.ScheduleToStartTimeout.Duration(), + StartToCloseTimeout: opts.StartToCloseTimeout.Duration(), + HeartbeatTimeout: opts.HeartbeatTimeout.Duration(), + Summary: opts.StaticSummary, + Details: opts.StaticDetails, + Priority: temporal.Priority{ + PriorityKey: opts.PriorityKey, + FairnessKey: opts.FairnessKey, + FairnessWeight: opts.FairnessWeight, + }, + } + if opts.RetryInitialInterval.Duration() > 0 || opts.RetryMaximumInterval.Duration() > 0 || + opts.RetryBackoffCoefficient > 0 || opts.RetryMaximumAttempts > 0 { + o.RetryPolicy = &temporal.RetryPolicy{ + InitialInterval: opts.RetryInitialInterval.Duration(), + MaximumInterval: opts.RetryMaximumInterval.Duration(), + BackoffCoefficient: float64(opts.RetryBackoffCoefficient), + MaximumAttempts: int32(opts.RetryMaximumAttempts), + } + } + if opts.IdReusePolicy.Value != "" { + var err error + o.ActivityIDReusePolicy, err = stringToProtoEnum[enumspb.ActivityIdReusePolicy]( + opts.IdReusePolicy.Value, enumspb.ActivityIdReusePolicy_shorthandValue, enumspb.ActivityIdReusePolicy_value) + if err != nil { + return o, fmt.Errorf("invalid activity ID reuse policy: %w", err) + } + } + if opts.IdConflictPolicy.Value != "" { + var err error + o.ActivityIDConflictPolicy, err = stringToProtoEnum[enumspb.ActivityIdConflictPolicy]( + opts.IdConflictPolicy.Value, enumspb.ActivityIdConflictPolicy_shorthandValue, enumspb.ActivityIdConflictPolicy_value) + if err != nil { + return o, fmt.Errorf("invalid activity ID conflict policy: %w", err) + } + } + if len(opts.SearchAttribute) > 0 { + saMap, err := stringKeysJSONValues(opts.SearchAttribute, false) + if err != nil { + return o, fmt.Errorf("invalid search attribute values: %w", err) + } + if o.TypedSearchAttributes, err = mapToSearchAttributes(saMap); err != nil { + return o, err + } + } + return o, nil +} + +// mapToSearchAttributes builds typed search attributes from a map produced by +// json.Unmarshal into map[string]any. The possible types from json.Unmarshal are: +// +// bool → NewSearchAttributeKeyBool (correct for Bool attributes) +// float64 → NewSearchAttributeKeyFloat64 (correct for Double; also used for Int, +// since JSON has a single number type) +// string → NewSearchAttributeKeyKeyword (correct for Keyword; also used for Text +// and Datetime, since JSON has a single string type) +// []any → NewSearchAttributeKeyKeywordList (each element must be string) +// map[string]any, nil → rejected (no corresponding SA type) +// +// For inputs where the payload type metadata doesn't match the registered type +// (Int registered but sent as Float64, Text/Datetime registered but sent as +// Keyword), the server decodes using its schema, not payload metadata, so these +// work correctly. +func mapToSearchAttributes(m map[string]any) (temporal.SearchAttributes, error) { + updates := make([]temporal.SearchAttributeUpdate, 0, len(m)) + for k, v := range m { + switch val := v.(type) { + case string: + updates = append(updates, temporal.NewSearchAttributeKeyKeyword(k).ValueSet(val)) + case float64: + updates = append(updates, temporal.NewSearchAttributeKeyFloat64(k).ValueSet(val)) + case bool: + updates = append(updates, temporal.NewSearchAttributeKeyBool(k).ValueSet(val)) + case []any: + strs := make([]string, len(val)) + for i, elem := range val { + s, ok := elem.(string) + if !ok { + return temporal.SearchAttributes{}, fmt.Errorf("search attribute %q: array element %d is %T, not string", k, i, elem) + } + strs[i] = s + } + updates = append(updates, temporal.NewSearchAttributeKeyKeywordList(k).ValueSet(strs)) + default: + return temporal.SearchAttributes{}, fmt.Errorf("unsupported search attribute type for key %q: %T", k, v) + } + } + return temporal.NewSearchAttributes(updates...), nil +} + +func getActivityResult(cctx *CommandContext, cl client.Client, namespace, activityID, runID string) error { + outcome, err := pollActivityOutcome(cctx, cl, namespace, activityID, runID) + if err != nil { + var notFound *serviceerror.NotFound + if errors.As(err, ¬Found) { + return fmt.Errorf("activity not found: %s", activityID) + } + return fmt.Errorf("failed polling activity result: %w", err) + } + + switch v := outcome.GetValue().(type) { + case *activitypb.ActivityExecutionOutcome_Result: + return printActivityResult(cctx, activityID, runID, v.Result) + case *activitypb.ActivityExecutionOutcome_Failure: + if err := printActivityFailure(cctx, activityID, runID, v.Failure); err != nil { + cctx.Logger.Error("Activity failed, and printing the output also failed", "error", err) + } + return fmt.Errorf("activity failed") + default: + return fmt.Errorf("unexpected activity outcome type: %T", v) + } +} + +// Matches the SDK's pollActivityTimeout in internal_activity_client.go. +const pollActivityTimeout = 60 * time.Second + +// pollActivityOutcome polls for an activity result using a hand-rolled loop +// rather than handle.Get() because handle.Get() deserializes the result into a +// Go value and converts failures to Go errors, losing the raw proto payloads. +// +// The per-request timeout matches the SDK's PollActivityResult implementation. +// Unlike the SDK, we retry at the application level on per-request timeout +// since we don't have the SDK's gRPC-level retry interceptor. +func pollActivityOutcome(cctx *CommandContext, cl client.Client, namespace, activityID, runID string) (*activitypb.ActivityExecutionOutcome, error) { + for { + pollCtx, cancel := context.WithTimeout(cctx, pollActivityTimeout) + resp, err := cl.WorkflowService().PollActivityExecution(pollCtx, &workflowservice.PollActivityExecutionRequest{ + Namespace: namespace, + ActivityId: activityID, + RunId: runID, + }) + if err != nil { + // check pollCtx.Err() first beause it is set by cancel() + pollTimedOut := pollCtx.Err() != nil + cancel() + if cctx.Err() != nil { + return nil, cctx.Err() + } + // Per-request timeout but parent still alive: retry. + if pollTimedOut { + continue + } + return nil, err + } + cancel() + if resp.GetOutcome() != nil { + return resp.GetOutcome(), nil + } + } +} + +func printActivityResult(cctx *CommandContext, activityID, runID string, result *common.Payloads) error { + if cctx.JSONOutput { + var resultJSON json.RawMessage + var err error + if cctx.JSONShorthandPayloads { + var valuePtr any + if err = converter.GetDefaultDataConverter().FromPayloads(result, &valuePtr); err != nil { + return fmt.Errorf("failed decoding result: %w", err) + } + resultJSON, err = json.Marshal(valuePtr) + } else { + resultJSON, err = cctx.MarshalProtoJSON(result) + } + if err != nil { + return fmt.Errorf("failed marshaling result: %w", err) + } + return cctx.Printer.PrintStructured(struct { + ActivityId string `json:"activityId"` + RunId string `json:"runId"` + Status string `json:"status"` + Result json.RawMessage `json:"result"` + }{ + ActivityId: activityID, + RunId: runID, + Status: "COMPLETED", + Result: resultJSON, + }, printer.StructuredOptions{}) + } + + cctx.Printer.Println(color.MagentaString("Results:")) + var valuePtr any + if err := converter.GetDefaultDataConverter().FromPayloads(result, &valuePtr); err != nil { + return fmt.Errorf("failed decoding result: %w", err) + } + resultJSON, err := json.Marshal(valuePtr) + if err != nil { + return fmt.Errorf("failed marshaling result: %w", err) + } + return cctx.Printer.PrintStructured(struct { + Status string + Result json.RawMessage `cli:",cardOmitEmpty"` + }{ + Status: color.GreenString("COMPLETED"), + Result: resultJSON, + }, printer.StructuredOptions{}) +} + +func printActivityFailure(cctx *CommandContext, activityID, runID string, f *failure.Failure) error { + if cctx.JSONOutput { + failureJSON, err := cctx.MarshalProtoJSON(f) + if err != nil { + return fmt.Errorf("failed marshaling failure: %w", err) + } + _ = cctx.Printer.PrintStructured(struct { + ActivityId string `json:"activityId"` + RunId string `json:"runId"` + Status string `json:"status"` + Failure json.RawMessage `json:"failure"` + }{ + ActivityId: activityID, + RunId: runID, + Status: "FAILED", + Failure: failureJSON, + }, printer.StructuredOptions{}) + return nil + } + + cctx.Printer.Println(color.MagentaString("Results:")) + _ = cctx.Printer.PrintStructured(struct { + Status string + Failure string `cli:",cardOmitEmpty"` + }{ + Status: color.RedString("FAILED"), + Failure: cctx.MarshalFriendlyFailureBodyText(f, " "), + }, printer.StructuredOptions{}) + return nil +} + +func (c *TemporalActivityDescribeCommand) run(cctx *CommandContext, args []string) error { + cl, err := dialClient(cctx, &c.Parent.ClientOptions) + if err != nil { + return err + } + defer cl.Close() + + handle := cl.GetActivityHandle(client.GetActivityHandleOptions{ + ActivityID: c.ActivityId, + RunID: c.RunId, + }) + desc, err := handle.Describe(cctx, client.DescribeActivityOptions{}) + if err != nil { + return fmt.Errorf("failed describing activity: %w", err) + } + if c.Raw || cctx.JSONOutput { + return cctx.Printer.PrintStructured(desc.RawExecutionInfo, printer.StructuredOptions{}) + } + return printActivityDescription(cctx, desc.RawExecutionInfo) +} + +func printActivityDescription(cctx *CommandContext, info *activitypb.ActivityExecutionInfo) error { + statusShorthand := func(s enumspb.ActivityExecutionStatus) string { + for name, val := range enumspb.ActivityExecutionStatus_shorthandValue { + if int32(s) == val { + return name + } + } + return s.String() + } + runStateShorthand := func(s enumspb.PendingActivityState) string { + for name, val := range enumspb.PendingActivityState_shorthandValue { + if int32(s) == val && name != "Unspecified" { + return name + } + } + return "" + } + + d := struct { + ActivityId string + RunId string + Type string + Status string + RunState string `cli:",cardOmitEmpty"` + TaskQueue string + ScheduleToCloseTimeout time.Duration `cli:",cardOmitEmpty"` + ScheduleToStartTimeout time.Duration `cli:",cardOmitEmpty"` + StartToCloseTimeout time.Duration `cli:",cardOmitEmpty"` + HeartbeatTimeout time.Duration `cli:",cardOmitEmpty"` + LastStartedTime time.Time `cli:",cardOmitEmpty"` + Attempt int32 + ExecutionDuration time.Duration `cli:",cardOmitEmpty"` + ScheduleTime time.Time `cli:",cardOmitEmpty"` + CloseTime time.Time `cli:",cardOmitEmpty"` + LastFailure string `cli:",cardOmitEmpty"` + LastWorkerIdentity string `cli:",cardOmitEmpty"` + LastAttemptCompleteTime time.Time `cli:",cardOmitEmpty"` + StateTransitionCount int64 + }{ + ActivityId: info.GetActivityId(), + RunId: info.GetRunId(), + Type: info.GetActivityType().GetName(), + Status: statusShorthand(info.GetStatus()), + RunState: runStateShorthand(info.GetRunState()), + TaskQueue: info.GetTaskQueue(), + ScheduleToCloseTimeout: info.GetScheduleToCloseTimeout().AsDuration(), + ScheduleToStartTimeout: info.GetScheduleToStartTimeout().AsDuration(), + StartToCloseTimeout: info.GetStartToCloseTimeout().AsDuration(), + HeartbeatTimeout: info.GetHeartbeatTimeout().AsDuration(), + LastStartedTime: timestampToTime(info.GetLastStartedTime()), + Attempt: info.GetAttempt(), + ExecutionDuration: info.GetExecutionDuration().AsDuration(), + ScheduleTime: timestampToTime(info.GetScheduleTime()), + CloseTime: timestampToTime(info.GetCloseTime()), + LastWorkerIdentity: info.GetLastWorkerIdentity(), + LastAttemptCompleteTime: timestampToTime(info.GetLastAttemptCompleteTime()), + StateTransitionCount: info.GetStateTransitionCount(), + } + if f := info.GetLastFailure(); f != nil { + d.LastFailure = cctx.MarshalFriendlyFailureBodyText(f, " ") + } + return cctx.Printer.PrintStructured(d, printer.StructuredOptions{}) +} + +func (c *TemporalActivityListCommand) run(cctx *CommandContext, args []string) error { + cl, err := dialClient(cctx, &c.Parent.ClientOptions) + if err != nil { + return err + } + defer cl.Close() + + if c.Limit > 0 && c.Limit < c.PageSize { + c.PageSize = c.Limit + } + + cctx.Printer.StartList() + defer cctx.Printer.EndList() + + var nextPageToken []byte + var execsProcessed int + for pageIndex := 0; ; pageIndex++ { + resp, err := cl.WorkflowService().ListActivityExecutions(cctx, &workflowservice.ListActivityExecutionsRequest{ + Namespace: c.Parent.Namespace, + PageSize: int32(c.PageSize), + NextPageToken: nextPageToken, + Query: c.Query, + }) + if err != nil { + return fmt.Errorf("failed listing activities: %w", err) + } + var textTable []map[string]any + for _, exec := range resp.Executions { + if c.Limit > 0 && execsProcessed >= c.Limit { + break + } + execsProcessed++ + if cctx.JSONOutput { + _ = cctx.Printer.PrintStructured(exec, printer.StructuredOptions{}) + } else { + textTable = append(textTable, map[string]any{ + "Status": exec.Status, + "ActivityId": exec.ActivityId, + "Type": exec.ActivityType.GetName(), + "StartTime": exec.ScheduleTime.AsTime(), + }) + } + } + if len(textTable) > 0 { + _ = cctx.Printer.PrintStructured(textTable, printer.StructuredOptions{ + Fields: []string{"Status", "ActivityId", "Type", "StartTime"}, + Table: &printer.TableOptions{NoHeader: pageIndex > 0}, + }) + } + nextPageToken = resp.NextPageToken + if len(nextPageToken) == 0 || (c.Limit > 0 && execsProcessed >= c.Limit) { + return nil + } + } +} + +func (c *TemporalActivityCountCommand) run(cctx *CommandContext, args []string) error { + cl, err := dialClient(cctx, &c.Parent.ClientOptions) + if err != nil { + return err + } + defer cl.Close() + + resp, err := cl.WorkflowService().CountActivityExecutions(cctx, &workflowservice.CountActivityExecutionsRequest{ + Namespace: c.Parent.Namespace, + Query: c.Query, + }) + if err != nil { + return fmt.Errorf("failed counting activities: %w", err) + } + groups := make([]countGroup, len(resp.Groups)) + for i, g := range resp.Groups { + groups[i] = g + } + if cctx.JSONOutput { + stripCountGroupMetadataType(groups) + return cctx.Printer.PrintStructured(resp, printer.StructuredOptions{}) + } + cctx.Printer.Printlnf("Total: %v", resp.Count) + printCountGroupsText(cctx, groups) + return nil +} + +func (c *TemporalActivityCancelCommand) run(cctx *CommandContext, args []string) error { + cl, err := dialClient(cctx, &c.Parent.ClientOptions) + if err != nil { + return err + } + defer cl.Close() + + handle := cl.GetActivityHandle(client.GetActivityHandleOptions{ + ActivityID: c.ActivityId, + RunID: c.RunId, + }) + if err := handle.Cancel(cctx, client.CancelActivityOptions{Reason: c.Reason}); err != nil { + return fmt.Errorf("failed to request activity cancellation: %w", err) + } + cctx.Printer.Println("Cancellation requested") + return nil +} + +func (c *TemporalActivityTerminateCommand) run(cctx *CommandContext, args []string) error { + cl, err := dialClient(cctx, &c.Parent.ClientOptions) + if err != nil { + return err + } + defer cl.Close() + + // The CLI adds a default for terminate but not cancel. + // This matches the behavior for workflows. + reason := c.Reason + if reason == "" { + reason = defaultReason() + } + handle := cl.GetActivityHandle(client.GetActivityHandleOptions{ + ActivityID: c.ActivityId, + RunID: c.RunId, + }) + // Terminate may fail if the activity doesn't exist or has already completed. + if err := handle.Terminate(cctx, client.TerminateActivityOptions{Reason: reason}); err != nil { + return fmt.Errorf("failed to terminate activity: %w", err) + } + cctx.Printer.Println("Activity terminated") + return nil +} + func (c *TemporalActivityCompleteCommand) run(cctx *CommandContext, args []string) error { cl, err := dialClient(cctx, &c.Parent.ClientOptions) if err != nil { diff --git a/internal/temporalcli/commands.activity_test.go b/internal/temporalcli/commands.activity_test.go index 28ff7a13b..c3ee80c6b 100644 --- a/internal/temporalcli/commands.activity_test.go +++ b/internal/temporalcli/commands.activity_test.go @@ -2,16 +2,20 @@ package temporalcli_test import ( "context" + "encoding/json" "fmt" + "strings" "sync" "sync/atomic" "time" + "github.com/google/uuid" "go.temporal.io/api/enums/v1" "go.temporal.io/api/history/v1" "go.temporal.io/api/serviceerror" "go.temporal.io/api/workflowservice/v1" "go.temporal.io/sdk/client" + "go.temporal.io/sdk/converter" "go.temporal.io/sdk/temporal" "go.temporal.io/sdk/workflow" "google.golang.org/grpc" @@ -519,3 +523,797 @@ func (s *SharedServerSuite) TestResetActivity_BatchSuccess() { // unblock the activities to let them finish failActivity.Store(false) } + +func (s *SharedServerSuite) TestActivity_Start() { + s.Worker().OnDevActivity(func(ctx context.Context, a any) (any, error) { + return "start-result", nil + }) + + res := s.Execute( + "activity", "start", + "--activity-id", "start-test", + "--type", "DevActivity", + "--task-queue", s.Worker().Options.TaskQueue, + "--start-to-close-timeout", "30s", + "--address", s.Address(), + ) + s.NoError(res.Err) + out := res.Stdout.String() + s.Contains(out, "Running execution:") + s.ContainsOnSameLine(out, "ActivityId", "start-test") + s.Contains(out, "RunId") + s.ContainsOnSameLine(out, "Type", "DevActivity") + s.ContainsOnSameLine(out, "Namespace", "default") + s.ContainsOnSameLine(out, "TaskQueue", s.Worker().Options.TaskQueue) + + // JSON + res = s.Execute( + "activity", "start", + "-o", "json", + "--activity-id", "start-test-json", + "--type", "DevActivity", + "--task-queue", s.Worker().Options.TaskQueue, + "--start-to-close-timeout", "30s", + "--address", s.Address(), + ) + s.NoError(res.Err) + var jsonOut map[string]any + s.NoError(json.Unmarshal(res.Stdout.Bytes(), &jsonOut)) + s.Equal("start-test-json", jsonOut["activityId"]) + s.NotEmpty(jsonOut["runId"]) + s.Equal("DevActivity", jsonOut["type"]) + s.Equal("default", jsonOut["namespace"]) + s.NotEmpty(jsonOut["taskQueue"]) +} + +func (s *SharedServerSuite) TestActivity_Start_With_Headers() { + s.Worker().OnDevActivity(func(ctx context.Context, a any) (any, error) { + return nil, nil + }) + + var capturedHeader *workflowservice.StartActivityExecutionRequest + var mu sync.Mutex + s.CommandHarness.Options.AdditionalClientGRPCDialOptions = append( + s.CommandHarness.Options.AdditionalClientGRPCDialOptions, + grpc.WithChainUnaryInterceptor(func( + ctx context.Context, + method string, req, reply any, + cc *grpc.ClientConn, invoker grpc.UnaryInvoker, opts ...grpc.CallOption, + ) error { + if startReq, ok := req.(*workflowservice.StartActivityExecutionRequest); ok { + mu.Lock() + capturedHeader = startReq + mu.Unlock() + } + return invoker(ctx, method, req, reply, cc, opts...) + }), + ) + + res := s.Execute( + "activity", "start", + "--activity-id", "header-test", + "--type", "DevActivity", + "--task-queue", s.Worker().Options.TaskQueue, + "--start-to-close-timeout", "30s", + "--headers", "id=123", + "--address", s.Address(), + ) + s.NoError(res.Err) + + mu.Lock() + defer mu.Unlock() + s.NotNil(capturedHeader) + payload := capturedHeader.Header.Fields["id"] + s.NotNil(payload) + var val int + s.NoError(converter.GetDefaultDataConverter().FromPayload(payload, &val)) + s.Equal(123, val) +} + +func (s *SharedServerSuite) TestActivity_Execute_Success() { + var receivedInput any + s.Worker().OnDevActivity(func(ctx context.Context, a any) (any, error) { + receivedInput = a + return map[string]string{"foo": "bar"}, nil + }) + + // Text + res := s.Execute( + "activity", "execute", + "--activity-id", "exec-test", + "--type", "DevActivity", + "--task-queue", s.Worker().Options.TaskQueue, + "--start-to-close-timeout", "30s", + "-i", `"my-input"`, + "--address", s.Address(), + ) + s.NoError(res.Err) + out := res.Stdout.String() + s.Contains(out, "Running execution:") + s.ContainsOnSameLine(out, "ActivityId", "exec-test") + s.Contains(out, "Results:") + s.ContainsOnSameLine(out, "Status", "COMPLETED") + s.ContainsOnSameLine(out, "Result", `{"foo":"bar"}`) + s.Equal("my-input", receivedInput) + + // JSON + res = s.Execute( + "activity", "execute", + "-o", "json", + "--activity-id", "exec-json-test", + "--type", "DevActivity", + "--task-queue", s.Worker().Options.TaskQueue, + "--start-to-close-timeout", "30s", + "--address", s.Address(), + ) + s.NoError(res.Err) + var jsonOut map[string]any + s.NoError(json.Unmarshal(res.Stdout.Bytes(), &jsonOut)) + s.Equal("exec-json-test", jsonOut["activityId"]) + s.NotEmpty(jsonOut["runId"]) + s.Equal("COMPLETED", jsonOut["status"]) + s.Equal(map[string]any{"foo": "bar"}, jsonOut["result"]) +} + +func (s *SharedServerSuite) TestActivity_Execute_Failure() { + s.Worker().OnDevActivity(func(ctx context.Context, a any) (any, error) { + return nil, fmt.Errorf("intentional failure") + }) + + // Text + res := s.Execute( + "activity", "execute", + "--activity-id", "exec-fail-test", + "--type", "DevActivity", + "--task-queue", s.Worker().Options.TaskQueue, + "--start-to-close-timeout", "30s", + "--retry-maximum-attempts", "1", + "--address", s.Address(), + ) + s.ErrorContains(res.Err, "activity failed") + out := res.Stdout.String() + s.Contains(out, "Running execution:") + s.Contains(out, "Results:") + s.Contains(out, "FAILED") + s.Contains(out, "intentional failure") + + // JSON + res = s.Execute( + "activity", "execute", + "-o", "json", + "--activity-id", "exec-fail-json-test", + "--type", "DevActivity", + "--task-queue", s.Worker().Options.TaskQueue, + "--start-to-close-timeout", "30s", + "--retry-maximum-attempts", "1", + "--address", s.Address(), + ) + s.Error(res.Err) + var jsonOut map[string]any + s.NoError(json.Unmarshal(res.Stdout.Bytes(), &jsonOut)) + s.Equal("exec-fail-json-test", jsonOut["activityId"]) + s.NotEmpty(jsonOut["runId"]) + s.Equal("FAILED", jsonOut["status"]) + failureObj, ok := jsonOut["failure"].(map[string]any) + s.True(ok, "failure should be a structured object, got: %T", jsonOut["failure"]) + s.Contains(failureObj["message"], "intentional failure") + s.NotNil(failureObj["applicationFailureInfo"]) +} + +func (s *SharedServerSuite) TestActivity_Execute_NoJsonShorthandPayloads() { + s.Worker().OnDevActivity(func(ctx context.Context, a any) (any, error) { + return map[string]string{"key": "val"}, nil + }) + + // With shorthand (default): result is decoded + res := s.Execute( + "activity", "execute", + "-o", "json", + "--activity-id", "shorthand-test", + "--type", "DevActivity", + "--task-queue", s.Worker().Options.TaskQueue, + "--start-to-close-timeout", "30s", + "--address", s.Address(), + ) + s.NoError(res.Err) + var jsonOut map[string]any + s.NoError(json.Unmarshal(res.Stdout.Bytes(), &jsonOut)) + s.Equal(map[string]any{"key": "val"}, jsonOut["result"]) + + // Without shorthand: result should be raw payloads with metadata/data + res = s.Execute( + "activity", "execute", + "-o", "json", + "--no-json-shorthand-payloads", + "--activity-id", "no-shorthand-test", + "--type", "DevActivity", + "--task-queue", s.Worker().Options.TaskQueue, + "--start-to-close-timeout", "30s", + "--address", s.Address(), + ) + s.NoError(res.Err) + s.NoError(json.Unmarshal(res.Stdout.Bytes(), &jsonOut)) + resultMap, ok := jsonOut["result"].(map[string]any) + s.True(ok, "result should be a payloads object, got: %T", jsonOut["result"]) + payloads, ok := resultMap["payloads"].([]any) + s.True(ok, "result should have payloads array") + s.Len(payloads, 1) + payload := payloads[0].(map[string]any) + s.NotNil(payload["metadata"]) + s.NotNil(payload["data"]) +} + +func (s *SharedServerSuite) TestActivity_Execute_RetriesOnEmptyPollResponse() { + // Activity sleeps longer than the server's activity.longPollTimeout (2s), + // forcing at least one empty poll response before the result arrives. + s.Worker().OnDevActivity(func(ctx context.Context, a any) (any, error) { + time.Sleep(3 * time.Second) + return "standalone-result", nil + }) + + res := s.Execute( + "activity", "execute", + "--activity-id", "poll-retry-test", + "--type", "DevActivity", + "--task-queue", s.Worker().Options.TaskQueue, + "--start-to-close-timeout", "30s", + "--address", s.Address(), + ) + s.NoError(res.Err) + s.Contains(res.Stdout.String(), "standalone-result") +} + +// startActivity starts an activity via the CLI and returns +// the parsed JSON response containing activityId and runId. +func (s *SharedServerSuite) startActivity(activityID string, extraArgs ...string) map[string]any { + args := []string{ + "activity", "start", + "-o", "json", + "--activity-id", activityID, + "--type", "DevActivity", + "--task-queue", s.Worker().Options.TaskQueue, + "--start-to-close-timeout", "30s", + "--address", s.Address(), + } + args = append(args, extraArgs...) + res := s.Execute(args...) + s.NoError(res.Err) + var jsonOut map[string]any + s.NoError(json.Unmarshal(res.Stdout.Bytes(), &jsonOut)) + return jsonOut +} + +func (s *SharedServerSuite) TestActivity_Result() { + s.Worker().OnDevActivity(func(ctx context.Context, a any) (any, error) { + return "result-value", nil + }) + + started := s.startActivity("result-test") + + res := s.Execute( + "activity", "result", + "--activity-id", "result-test", + "--run-id", started["runId"].(string), + "--address", s.Address(), + ) + s.NoError(res.Err) + s.Contains(res.Stdout.String(), "result-value") + + // JSON output without --run-id + res = s.Execute( + "activity", "result", + "-o", "json", + "--activity-id", "result-test", + "--address", s.Address(), + ) + s.NoError(res.Err) + var jsonOut map[string]any + s.NoError(json.Unmarshal(res.Stdout.Bytes(), &jsonOut)) + s.Equal("COMPLETED", jsonOut["status"]) + s.Equal("result-test", jsonOut["activityId"]) + s.Equal("result-value", jsonOut["result"]) +} + +func (s *SharedServerSuite) TestActivity_Result_NotFound() { + res := s.Execute( + "activity", "result", + "--activity-id", "nonexistent-activity-id", + "--address", s.Address(), + ) + s.Error(res.Err) + s.Contains(res.Err.Error(), "not found") + s.NotContains(res.Stdout.String(), "FAILED") +} + +func (s *SharedServerSuite) TestActivity_Describe() { + activityStarted := make(chan struct{}) + s.Worker().OnDevActivity(func(ctx context.Context, a any) (any, error) { + close(activityStarted) + <-ctx.Done() + return nil, ctx.Err() + }) + + started := s.startActivity("describe-test", + "--schedule-to-close-timeout", "300s", + "--schedule-to-start-timeout", "60s", + "--heartbeat-timeout", "15s", + "--retry-maximum-attempts", "5", + "--retry-initial-interval", "2s", + "--retry-backoff-coefficient", "3", + "--retry-maximum-interval", "120s", + ) + runID := started["runId"].(string) + <-activityStarted + + // Text + res := s.Execute( + "activity", "describe", + "--activity-id", "describe-test", + "--run-id", runID, + "--address", s.Address(), + ) + s.NoError(res.Err) + out := res.Stdout.String() + s.ContainsOnSameLine(out, "ActivityId", "describe-test") + s.ContainsOnSameLine(out, "Type", "DevActivity") + s.ContainsOnSameLine(out, "Status", "Running") + s.ContainsOnSameLine(out, "TaskQueue", s.Worker().Options.TaskQueue) + s.ContainsOnSameLine(out, "StartToCloseTimeout", "30s") + s.ContainsOnSameLine(out, "ScheduleToCloseTimeout", "5m0s") + s.ContainsOnSameLine(out, "ScheduleToStartTimeout", "1m0s") + s.ContainsOnSameLine(out, "HeartbeatTimeout", "15s") + s.ContainsOnSameLine(out, "Attempt", "1") + s.Contains(out, "LastWorkerIdentity") + s.NotContains(out, `{"name":`) + + // JSON + res = s.Execute( + "activity", "describe", + "-o", "json", + "--activity-id", "describe-test", + "--run-id", runID, + "--address", s.Address(), + ) + s.NoError(res.Err) + var jsonOut map[string]any + s.NoError(json.Unmarshal(res.Stdout.Bytes(), &jsonOut)) + s.Equal("describe-test", jsonOut["activityId"]) + s.NotNil(jsonOut["activityType"]) + s.NotNil(jsonOut["taskQueue"]) + s.Equal("300s", jsonOut["scheduleToCloseTimeout"]) + s.Equal("60s", jsonOut["scheduleToStartTimeout"]) + s.Equal("30s", jsonOut["startToCloseTimeout"]) + s.Equal("15s", jsonOut["heartbeatTimeout"]) + retryPolicy, ok := jsonOut["retryPolicy"].(map[string]any) + s.True(ok, "retryPolicy should be present in JSON describe") + s.Equal(float64(5), retryPolicy["maximumAttempts"]) + s.Equal("2s", retryPolicy["initialInterval"]) + s.Equal(float64(3), retryPolicy["backoffCoefficient"]) + s.Equal("120s", retryPolicy["maximumInterval"]) + + // Raw: should contain proto JSON format + res = s.Execute( + "activity", "describe", + "--raw", + "--activity-id", "describe-test", + "--run-id", runID, + "--address", s.Address(), + ) + s.NoError(res.Err) + rawOut := res.Stdout.String() + s.Contains(rawOut, "describe-test") + s.Contains(rawOut, `{"name":"DevActivity"}`) +} + +// Text-only: verifies LastFailure is rendered as text not JSON. +func (s *SharedServerSuite) TestActivity_Describe_FailedLastFailure() { + s.Worker().OnDevActivity(func(ctx context.Context, a any) (any, error) { + return nil, fmt.Errorf("describe-failure-msg") + }) + + started := s.startActivity("describe-fail-test", "--retry-maximum-attempts", "1") + + // Wait for the activity to fail + handle := s.Client.GetActivityHandle(client.GetActivityHandleOptions{ + ActivityID: "describe-fail-test", + RunID: started["runId"].(string), + }) + _ = handle.Get(s.Context, nil) + + res := s.Execute( + "activity", "describe", + "--activity-id", "describe-fail-test", + "--run-id", started["runId"].(string), + "--address", s.Address(), + ) + s.NoError(res.Err) + out := res.Stdout.String() + // LastFailure should be human-readable, not raw JSON + s.Contains(out, "describe-failure-msg") + s.NotContains(out, `"message":"describe-failure-msg"`) +} + +func (s *SharedServerSuite) TestActivity_List() { + s.Worker().OnDevActivity(func(ctx context.Context, a any) (any, error) { + return "listed", nil + }) + + s.startActivity("list-test-1") + s.startActivity("list-test-2") + s.startActivity("list-test-3") + + // Wait for all three to be visible + s.Eventually(func() bool { + res := s.Execute( + "activity", "list", + "--address", s.Address(), + ) + out := res.Stdout.String() + return res.Err == nil && + strings.Contains(out, "list-test-1") && + strings.Contains(out, "list-test-2") && + strings.Contains(out, "list-test-3") + }, 5*time.Second, 200*time.Millisecond) + + // --limit should cap the number of results + res := s.Execute( + "activity", "list", + "--limit", "2", + "--address", s.Address(), + ) + s.NoError(res.Err) + lines := strings.Split(strings.TrimSpace(res.Stdout.String()), "\n") + s.Equal(3, len(lines), "expected header + 2 rows with --limit 2, got: %s", res.Stdout.String()) + + // JSON + res = s.Execute( + "activity", "list", + "-o", "json", + "--address", s.Address(), + ) + s.NoError(res.Err) + out := res.Stdout.String() + s.ContainsOnSameLine(out, "activityId", "list-test-1") + s.ContainsOnSameLine(out, "status", "ACTIVITY_EXECUTION_STATUS_COMPLETED") +} + +func (s *SharedServerSuite) TestActivity_Count() { + s.Worker().OnDevActivity(func(ctx context.Context, a any) (any, error) { + return "counted", nil + }) + + s.startActivity("count-test") + + // Text + s.Eventually(func() bool { + res := s.Execute( + "activity", "count", + "--address", s.Address(), + ) + return res.Err == nil && strings.Contains(res.Stdout.String(), "Total:") + }, 5*time.Second, 200*time.Millisecond) + + // Grouped text + s.Eventually(func() bool { + res := s.Execute( + "activity", "count", + "--address", s.Address(), + "--query", "GROUP BY ExecutionStatus", + ) + if res.Err != nil { + return false + } + out := res.Stdout.String() + return strings.Contains(out, "Total:") && strings.Contains(out, "Group total:") + }, 5*time.Second, 200*time.Millisecond) + + // JSON + res := s.Execute( + "activity", "count", + "--address", s.Address(), + "-o", "json", + ) + s.NoError(res.Err) + var jsonOut map[string]any + s.NoError(json.Unmarshal(res.Stdout.Bytes(), &jsonOut)) + _, ok := jsonOut["count"] + s.True(ok) +} + +// No JSON variant: command produces no output on success in any mode. +func (s *SharedServerSuite) TestActivity_Complete_ByRunId() { + activityStarted := make(chan struct{}) + s.Worker().OnDevActivity(func(ctx context.Context, a any) (any, error) { + close(activityStarted) + <-ctx.Done() + return nil, ctx.Err() + }) + + started := s.startActivity("sa-complete-test") + runID := started["runId"].(string) + <-activityStarted + + res := s.Execute( + "activity", "complete", + "--activity-id", "sa-complete-test", + "--run-id", runID, + "--result", `"completed-externally"`, + "--identity", identity, + "--address", s.Address(), + ) + s.NoError(res.Err) + + handle := s.Client.GetActivityHandle(client.GetActivityHandleOptions{ + ActivityID: "sa-complete-test", + RunID: runID, + }) + var actual string + s.NoError(handle.Get(s.Context, &actual)) + s.Equal("completed-externally", actual) +} + +// No JSON variant: command produces no output on success in any mode. +func (s *SharedServerSuite) TestActivity_Fail_ByRunId() { + activityStarted := make(chan struct{}) + s.Worker().OnDevActivity(func(ctx context.Context, a any) (any, error) { + close(activityStarted) + <-ctx.Done() + return nil, ctx.Err() + }) + + started := s.startActivity("sa-fail-test") + runID := started["runId"].(string) + <-activityStarted + + res := s.Execute( + "activity", "fail", + "--activity-id", "sa-fail-test", + "--run-id", runID, + "--reason", "external-failure", + "--identity", identity, + "--address", s.Address(), + ) + s.NoError(res.Err) + + handle := s.Client.GetActivityHandle(client.GetActivityHandleOptions{ + ActivityID: "sa-fail-test", + RunID: runID, + }) + err := handle.Get(s.Context, nil) + s.Error(err) + s.Contains(err.Error(), "external-failure") +} + +// No JSON variant: Println outputs the same text regardless of -o json (matches workflow cancel). +func (s *SharedServerSuite) TestActivity_Cancel() { + activityStarted := make(chan struct{}) + s.Worker().OnDevActivity(func(ctx context.Context, a any) (any, error) { + close(activityStarted) + <-ctx.Done() + return nil, ctx.Err() + }) + + started := s.startActivity("cancel-test") + runID := started["runId"].(string) + <-activityStarted + + res := s.Execute( + "activity", "cancel", + "--activity-id", "cancel-test", + "--run-id", runID, + "--reason", "test-cancel", + "--address", s.Address(), + ) + s.NoError(res.Err) + s.Contains(res.Stdout.String(), "Cancellation requested") + + handle := s.Client.GetActivityHandle(client.GetActivityHandleOptions{ + ActivityID: "cancel-test", + RunID: runID, + }) + s.Eventually(func() bool { + desc, err := handle.Describe(s.Context, client.DescribeActivityOptions{}) + return err == nil && desc.RunState.String() == "CancelRequested" + }, 5*time.Second, 100*time.Millisecond) +} + +// No JSON variant: Println outputs the same text regardless of -o json (matches workflow terminate). +func (s *SharedServerSuite) TestActivity_Terminate() { + activityStarted := make(chan struct{}) + s.Worker().OnDevActivity(func(ctx context.Context, a any) (any, error) { + close(activityStarted) + <-ctx.Done() + return nil, ctx.Err() + }) + + started := s.startActivity("terminate-test") + runID := started["runId"].(string) + <-activityStarted + + res := s.Execute( + "activity", "terminate", + "--activity-id", "terminate-test", + "--run-id", runID, + "--reason", "test-terminate", + "--address", s.Address(), + ) + s.NoError(res.Err) + s.Contains(res.Stdout.String(), "Activity terminated") + + handle := s.Client.GetActivityHandle(client.GetActivityHandleOptions{ + ActivityID: "terminate-test", + RunID: runID, + }) + err := handle.Get(s.Context, nil) + s.Error(err) + s.Contains(err.Error(), "terminated") +} + +func (s *SharedServerSuite) TestActivity_SearchAttributes() { + s.Worker().OnDevActivity(func(ctx context.Context, a any) (any, error) { + return nil, nil + }) + + for _, sa := range []struct{ name, typ string }{ + {"SATestBool", "Bool"}, + {"SATestInt", "Int"}, + {"SATestDouble", "Double"}, + {"SATestKeyword", "Keyword"}, + {"SATestText", "Text"}, + {"SATestKeywordList", "KeywordList"}, + } { + res := s.Execute( + "operator", "search-attribute", "create", + "--address", s.Address(), + "--name", sa.name, + "--type", sa.typ, + ) + s.NoError(res.Err) + } + + unique := uuid.NewString()[:8] + + // Bool (JSON bool → NewSearchAttributeKeyBool) + s.startActivity("sa-bool-"+unique, + "--search-attribute", `SATestBool=true`, + ) + s.Eventually(func() bool { + res := s.Execute("activity", "list", "--address", s.Address(), + "--query", `SATestBool = true`) + return res.Err == nil && strings.Contains(res.Stdout.String(), "sa-bool-"+unique) + }, 5*time.Second, 200*time.Millisecond) + + // Int (JSON number → float64 → sent as Float64; server decodes via schema) + s.startActivity("sa-int-"+unique, + "--search-attribute", `SATestInt=42`, + ) + s.Eventually(func() bool { + res := s.Execute("activity", "list", "--address", s.Address(), + "--query", `SATestInt = 42`) + return res.Err == nil && strings.Contains(res.Stdout.String(), "sa-int-"+unique) + }, 5*time.Second, 200*time.Millisecond) + + // Double (JSON number → float64 → NewSearchAttributeKeyFloat64) + s.startActivity("sa-double-"+unique, + "--search-attribute", `SATestDouble=3.14`, + ) + s.Eventually(func() bool { + res := s.Execute("activity", "list", "--address", s.Address(), + "--query", `SATestDouble = 3.14`) + return res.Err == nil && strings.Contains(res.Stdout.String(), "sa-double-"+unique) + }, 5*time.Second, 200*time.Millisecond) + + // Keyword (JSON string → NewSearchAttributeKeyKeyword) + s.startActivity("sa-keyword-"+unique, + "--search-attribute", fmt.Sprintf(`SATestKeyword="kw-%s"`, unique), + ) + s.Eventually(func() bool { + res := s.Execute("activity", "list", "--address", s.Address(), + "--query", fmt.Sprintf(`SATestKeyword = "kw-%s"`, unique)) + return res.Err == nil && strings.Contains(res.Stdout.String(), "sa-keyword-"+unique) + }, 5*time.Second, 200*time.Millisecond) + + // Text (JSON string → sent as Keyword; server decodes via schema) + s.startActivity("sa-text-"+unique, + "--search-attribute", fmt.Sprintf(`SATestText="text value %s"`, unique), + ) + s.Eventually(func() bool { + res := s.Execute("activity", "list", "--address", s.Address(), + "--query", fmt.Sprintf(`SATestText = "text value %s"`, unique)) + return res.Err == nil && strings.Contains(res.Stdout.String(), "sa-text-"+unique) + }, 5*time.Second, 200*time.Millisecond) + + // KeywordList (JSON array → []any → NewSearchAttributeKeyKeywordList) + s.startActivity("sa-kwlist-"+unique, + "--search-attribute", `SATestKeywordList=["alpha","beta"]`, + ) + s.Eventually(func() bool { + res := s.Execute("activity", "list", "--address", s.Address(), + "--query", `SATestKeywordList = "alpha"`) + return res.Err == nil && strings.Contains(res.Stdout.String(), "sa-kwlist-"+unique) + }, 5*time.Second, 200*time.Millisecond) +} + +func (s *SharedServerSuite) TestActivity_SearchAttributes_Datetime() { + s.Worker().OnDevActivity(func(ctx context.Context, a any) (any, error) { + return nil, nil + }) + + res := s.Execute( + "operator", "search-attribute", "create", + "--address", s.Address(), + "--name", "SATestDatetime", + "--type", "Datetime", + ) + s.NoError(res.Err) + + s.startActivity("sa-datetime-test", + "--search-attribute", `SATestDatetime="2024-01-15T00:00:00Z"`, + ) + s.Eventually(func() bool { + res = s.Execute( + "activity", "list", + "--address", s.Address(), + "--query", `SATestDatetime > "2024-01-14T00:00:00Z"`, + ) + return res.Err == nil && strings.Contains(res.Stdout.String(), "sa-datetime-test") + }, 5*time.Second, 200*time.Millisecond) +} + +func (s *SharedServerSuite) TestActivity_SearchAttributes_InvalidKeywordList() { + res := s.Execute( + "activity", "start", + "--activity-id", "sa-invalid-kwlist", + "--type", "DevActivity", + "--task-queue", s.Worker().Options.TaskQueue, + "--start-to-close-timeout", "30s", + "--search-attribute", `Foo=[1,"a"]`, + "--address", s.Address(), + ) + s.Error(res.Err) + s.Contains(res.Err.Error(), "array element 0 is float64, not string") +} + +func (s *SharedServerSuite) TestActivity_List_Pagination() { + s.Worker().OnDevActivity(func(ctx context.Context, a any) (any, error) { + return "paginated", nil + }) + + uniqueKW := "page-" + uuid.NewString()[:8] + for i := 0; i < 5; i++ { + s.startActivity(fmt.Sprintf("page-test-%d", i), + "--search-attribute", fmt.Sprintf(`CustomKeywordField="%s"`, uniqueKW), + ) + } + + // Wait for all 5 to be visible + s.Eventually(func() bool { + res := s.Execute( + "activity", "list", + "--address", s.Address(), + "--query", fmt.Sprintf(`CustomKeywordField = "%s"`, uniqueKW), + ) + return res.Err == nil && strings.Count(res.Stdout.String(), "page-test-") >= 5 + }, 5*time.Second, 200*time.Millisecond) + + // Small page size forces multi-page fetching; verify all 5 appear + res := s.Execute( + "activity", "list", + "--page-size", "2", + "--address", s.Address(), + "--query", fmt.Sprintf(`CustomKeywordField = "%s"`, uniqueKW), + ) + s.NoError(res.Err) + s.Equal(5, strings.Count(res.Stdout.String(), "page-test-")) + + // --limit 3 with page-size 2 should return exactly 3 + res = s.Execute( + "activity", "list", + "--page-size", "2", + "--limit", "3", + "--address", s.Address(), + "--query", fmt.Sprintf(`CustomKeywordField = "%s"`, uniqueKW), + ) + s.NoError(res.Err) + s.Equal(3, strings.Count(res.Stdout.String(), "page-test-")) +} diff --git a/internal/temporalcli/commands.gen.go b/internal/temporalcli/commands.gen.go index 1b1f31295..b70bec6be 100644 --- a/internal/temporalcli/commands.gen.go +++ b/internal/temporalcli/commands.gen.go @@ -348,6 +348,78 @@ func (v *WorkflowUpdateOptionsOptions) BuildFlags(f *pflag.FlagSet) { f.StringVar(&v.VersioningOverrideBuildId, "versioning-override-build-id", "", "When overriding to a `pinned` behavior, specifies the Build ID of the version to target.") } +type ActivityReferenceOptions struct { + ActivityId string + RunId string + FlagSet *pflag.FlagSet +} + +func (v *ActivityReferenceOptions) BuildFlags(f *pflag.FlagSet) { + v.FlagSet = f + f.StringVarP(&v.ActivityId, "activity-id", "a", "", "Activity ID. Required.") + _ = cobra.MarkFlagRequired(f, "activity-id") + f.StringVarP(&v.RunId, "run-id", "r", "", "Activity Run ID. If not set, targets the latest run.") +} + +type ActivityStartOptions struct { + ActivityId string + Type string + TaskQueue string + ScheduleToCloseTimeout cliext.FlagDuration + ScheduleToStartTimeout cliext.FlagDuration + StartToCloseTimeout cliext.FlagDuration + HeartbeatTimeout cliext.FlagDuration + RetryInitialInterval cliext.FlagDuration + RetryMaximumInterval cliext.FlagDuration + RetryBackoffCoefficient float32 + RetryMaximumAttempts int + IdReusePolicy cliext.FlagStringEnum + IdConflictPolicy cliext.FlagStringEnum + SearchAttribute []string + Headers []string + StaticSummary string + StaticDetails string + PriorityKey int + FairnessKey string + FairnessWeight float32 + FlagSet *pflag.FlagSet +} + +func (v *ActivityStartOptions) BuildFlags(f *pflag.FlagSet) { + v.FlagSet = f + f.StringVarP(&v.ActivityId, "activity-id", "a", "", "Activity ID. Required.") + _ = cobra.MarkFlagRequired(f, "activity-id") + f.StringVar(&v.Type, "type", "", "Activity Type name. Required.") + _ = cobra.MarkFlagRequired(f, "type") + f.StringVarP(&v.TaskQueue, "task-queue", "t", "", "Activity Task queue. Required.") + _ = cobra.MarkFlagRequired(f, "task-queue") + v.ScheduleToCloseTimeout = 0 + f.Var(&v.ScheduleToCloseTimeout, "schedule-to-close-timeout", "Maximum time for the Activity Execution, including all retries. Either this or \"start-to-close-timeout\" is required.") + v.ScheduleToStartTimeout = 0 + f.Var(&v.ScheduleToStartTimeout, "schedule-to-start-timeout", "Maximum time an Activity task can stay in a task queue before a Worker picks it up.") + v.StartToCloseTimeout = 0 + f.Var(&v.StartToCloseTimeout, "start-to-close-timeout", "Maximum time for a single Activity attempt. Either this or \"schedule-to-close-timeout\" is required.") + v.HeartbeatTimeout = 0 + f.Var(&v.HeartbeatTimeout, "heartbeat-timeout", "Maximum time between successful Worker heartbeats.") + v.RetryInitialInterval = 0 + f.Var(&v.RetryInitialInterval, "retry-initial-interval", "Interval of the first retry. If \"retry-backoff-coefficient\" is 1.0, it is used for all retries.") + v.RetryMaximumInterval = 0 + f.Var(&v.RetryMaximumInterval, "retry-maximum-interval", "Maximum interval between retries.") + f.Float32Var(&v.RetryBackoffCoefficient, "retry-backoff-coefficient", 0, "Coefficient for calculating the next retry interval. Must be 1 or larger.") + f.IntVar(&v.RetryMaximumAttempts, "retry-maximum-attempts", 0, "Maximum number of attempts. Setting to 1 disables retries. Setting to 0 means unlimited attempts.") + v.IdReusePolicy = cliext.NewFlagStringEnum([]string{"AllowDuplicate", "AllowDuplicateFailedOnly", "RejectDuplicate"}, "") + f.Var(&v.IdReusePolicy, "id-reuse-policy", "Policy for handling activity start when an Activity with the same ID exists and has completed. Accepted values: AllowDuplicate, AllowDuplicateFailedOnly, RejectDuplicate.") + v.IdConflictPolicy = cliext.NewFlagStringEnum([]string{"Fail", "UseExisting"}, "") + f.Var(&v.IdConflictPolicy, "id-conflict-policy", "Policy for handling activity start when an Activity with the same ID is currently running. Accepted values: Fail, UseExisting.") + f.StringArrayVar(&v.SearchAttribute, "search-attribute", nil, "Search Attribute in `KEY=VALUE` format. Keys must be identifiers, and values must be JSON values. Can be passed multiple times. See https://docs.temporal.io/visibility.") + f.StringArrayVar(&v.Headers, "headers", nil, "Temporal activity headers in 'KEY=VALUE' format. Keys must be identifiers, and values must be JSON values. May be passed multiple times.") + f.StringVar(&v.StaticSummary, "static-summary", "", "Static Activity summary for human consumption in UIs. Uses standard Markdown formatting excluding images, HTML, and script tags. EXPERIMENTAL.") + f.StringVar(&v.StaticDetails, "static-details", "", "Static Activity details for human consumption in UIs. Uses standard Markdown formatting excluding images, HTML, and script tags. EXPERIMENTAL.") + f.IntVar(&v.PriorityKey, "priority-key", 0, "Priority key (1-5, lower = higher priority). Default is 3 when not specified.") + f.StringVar(&v.FairnessKey, "fairness-key", "", "Fairness key (max 64 bytes) for proportional task dispatch.") + f.Float32Var(&v.FairnessWeight, "fairness-weight", 0, "Weight [0.001-1000] for this fairness key.") +} + type TemporalCommand struct { Command cobra.Command cliext.CommonOptions @@ -388,28 +460,62 @@ func NewTemporalActivityCommand(cctx *CommandContext, parent *TemporalCommand) * var s TemporalActivityCommand s.Parent = parent s.Command.Use = "activity" - s.Command.Short = "Complete, update, pause, unpause, reset or fail an Activity" - if hasHighlighting { - s.Command.Long = "Update an Activity's options, manage activity lifecycle or update\nan Activity's state to completed or failed.\n\nUpdating activity state marks an Activity as successfully finished or as\nhaving encountered an error.\n\n\x1b[1mtemporal activity complete \\\n --activity-id=YourActivityId \\\n --workflow-id=YourWorkflowId \\\n --result='{\"YourResultKey\": \"YourResultValue\"}'\x1b[0m" - } else { - s.Command.Long = "Update an Activity's options, manage activity lifecycle or update\nan Activity's state to completed or failed.\n\nUpdating activity state marks an Activity as successfully finished or as\nhaving encountered an error.\n\n```\ntemporal activity complete \\\n --activity-id=YourActivityId \\\n --workflow-id=YourWorkflowId \\\n --result='{\"YourResultKey\": \"YourResultValue\"}'\n```" - } + s.Command.Short = "Operate on Activity Executions" + s.Command.Long = "Perform operations on Activity Executions." s.Command.Args = cobra.NoArgs + s.Command.AddCommand(&NewTemporalActivityCancelCommand(cctx, &s).Command) s.Command.AddCommand(&NewTemporalActivityCompleteCommand(cctx, &s).Command) + s.Command.AddCommand(&NewTemporalActivityCountCommand(cctx, &s).Command) + s.Command.AddCommand(&NewTemporalActivityDescribeCommand(cctx, &s).Command) + s.Command.AddCommand(&NewTemporalActivityExecuteCommand(cctx, &s).Command) s.Command.AddCommand(&NewTemporalActivityFailCommand(cctx, &s).Command) + s.Command.AddCommand(&NewTemporalActivityListCommand(cctx, &s).Command) s.Command.AddCommand(&NewTemporalActivityPauseCommand(cctx, &s).Command) s.Command.AddCommand(&NewTemporalActivityResetCommand(cctx, &s).Command) + s.Command.AddCommand(&NewTemporalActivityResultCommand(cctx, &s).Command) + s.Command.AddCommand(&NewTemporalActivityStartCommand(cctx, &s).Command) + s.Command.AddCommand(&NewTemporalActivityTerminateCommand(cctx, &s).Command) s.Command.AddCommand(&NewTemporalActivityUnpauseCommand(cctx, &s).Command) s.Command.AddCommand(&NewTemporalActivityUpdateOptionsCommand(cctx, &s).Command) s.ClientOptions.BuildFlags(s.Command.PersistentFlags()) return &s } -type TemporalActivityCompleteCommand struct { +type TemporalActivityCancelCommand struct { Parent *TemporalActivityCommand Command cobra.Command - WorkflowReferenceOptions + ActivityReferenceOptions + Reason string +} + +func NewTemporalActivityCancelCommand(cctx *CommandContext, parent *TemporalActivityCommand) *TemporalActivityCancelCommand { + var s TemporalActivityCancelCommand + s.Parent = parent + s.Command.DisableFlagsInUseLine = true + s.Command.Use = "cancel [flags]" + s.Command.Short = "Request cancellation of a Standalone Activity (Experimental)" + if hasHighlighting { + s.Command.Long = "Request cancellation of a Standalone Activity.\n\n\x1b[1mtemporal activity cancel \\\n --activity-id YourActivityId\x1b[0m\n\nRequesting cancellation transitions the Activity's run state\nto CancelRequested. If the Activity is heartbeating, a\ncancellation error will be raised when the next heartbeat\nresponse is received; if the Activity allows this error to\npropagate, the Activity transitions to canceled status." + } else { + s.Command.Long = "Request cancellation of a Standalone Activity.\n\n```\ntemporal activity cancel \\\n --activity-id YourActivityId\n```\n\nRequesting cancellation transitions the Activity's run state\nto CancelRequested. If the Activity is heartbeating, a\ncancellation error will be raised when the next heartbeat\nresponse is received; if the Activity allows this error to\npropagate, the Activity transitions to canceled status." + } + s.Command.Args = cobra.NoArgs + s.Command.Flags().StringVar(&s.Reason, "reason", "", "Reason for cancellation.") + s.ActivityReferenceOptions.BuildFlags(s.Command.Flags()) + s.Command.Run = func(c *cobra.Command, args []string) { + if err := s.run(cctx, args); err != nil { + cctx.Options.Fail(err) + } + } + return &s +} + +type TemporalActivityCompleteCommand struct { + Parent *TemporalActivityCommand + Command cobra.Command ActivityId string + WorkflowId string + RunId string Result string } @@ -418,18 +524,19 @@ func NewTemporalActivityCompleteCommand(cctx *CommandContext, parent *TemporalAc s.Parent = parent s.Command.DisableFlagsInUseLine = true s.Command.Use = "complete [flags]" - s.Command.Short = "Complete an Activity" + s.Command.Short = "Mark an activity as completed successfully with a result" if hasHighlighting { s.Command.Long = "Complete an Activity, marking it as successfully finished. Specify the\nActivity ID and include a JSON result for the returned value:\n\n\x1b[1mtemporal activity complete \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId \\\n --result '{\"YourResultKey\": \"YourResultVal\"}'\x1b[0m" } else { s.Command.Long = "Complete an Activity, marking it as successfully finished. Specify the\nActivity ID and include a JSON result for the returned value:\n\n```\ntemporal activity complete \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId \\\n --result '{\"YourResultKey\": \"YourResultVal\"}'\n```" } s.Command.Args = cobra.NoArgs - s.Command.Flags().StringVar(&s.ActivityId, "activity-id", "", "Activity ID to complete. Required.") + s.Command.Flags().StringVarP(&s.ActivityId, "activity-id", "a", "", "Activity ID. This may be the ID of an Activity invoked by a Workflow, or of a Standalone Activity. Required.") _ = cobra.MarkFlagRequired(s.Command.Flags(), "activity-id") + s.Command.Flags().StringVarP(&s.WorkflowId, "workflow-id", "w", "", "Workflow ID. Required for workflow Activities. Omit for Standalone Activities.") + s.Command.Flags().StringVarP(&s.RunId, "run-id", "r", "", "Run ID. For workflow Activities (when --workflow-id is provided), this is the Workflow Run ID. For Standalone Activities, this is the Activity Run ID.") s.Command.Flags().StringVar(&s.Result, "result", "", "Result `JSON` to return. Required.") _ = cobra.MarkFlagRequired(s.Command.Flags(), "result") - s.WorkflowReferenceOptions.BuildFlags(s.Command.Flags()) s.Command.Run = func(c *cobra.Command, args []string) { if err := s.run(cctx, args); err != nil { cctx.Options.Fail(err) @@ -438,11 +545,97 @@ func NewTemporalActivityCompleteCommand(cctx *CommandContext, parent *TemporalAc return &s } -type TemporalActivityFailCommand struct { +type TemporalActivityCountCommand struct { Parent *TemporalActivityCommand Command cobra.Command - WorkflowReferenceOptions + Query string +} + +func NewTemporalActivityCountCommand(cctx *CommandContext, parent *TemporalActivityCommand) *TemporalActivityCountCommand { + var s TemporalActivityCountCommand + s.Parent = parent + s.Command.DisableFlagsInUseLine = true + s.Command.Use = "count [flags]" + s.Command.Short = "Count Standalone Activities matching a query (Experimental)" + if hasHighlighting { + s.Command.Long = "Return a count of Standalone Activities. Use \x1b[1m--query\x1b[0m to filter\nthe activities to be counted.\n\n\x1b[1mtemporal activity count \\\n --query 'ActivityType=\"YourActivity\"'\x1b[0m\n\nVisit https://docs.temporal.io/visibility to read more about\nSearch Attributes and queries." + } else { + s.Command.Long = "Return a count of Standalone Activities. Use `--query` to filter\nthe activities to be counted.\n\n```\ntemporal activity count \\\n --query 'ActivityType=\"YourActivity\"'\n```\n\nVisit https://docs.temporal.io/visibility to read more about\nSearch Attributes and queries." + } + s.Command.Args = cobra.NoArgs + s.Command.Flags().StringVarP(&s.Query, "query", "q", "", "Query to filter Activity Executions to count.") + s.Command.Run = func(c *cobra.Command, args []string) { + if err := s.run(cctx, args); err != nil { + cctx.Options.Fail(err) + } + } + return &s +} + +type TemporalActivityDescribeCommand struct { + Parent *TemporalActivityCommand + Command cobra.Command + ActivityReferenceOptions + Raw bool +} + +func NewTemporalActivityDescribeCommand(cctx *CommandContext, parent *TemporalActivityCommand) *TemporalActivityDescribeCommand { + var s TemporalActivityDescribeCommand + s.Parent = parent + s.Command.DisableFlagsInUseLine = true + s.Command.Use = "describe [flags]" + s.Command.Short = "Show detailed info for a Standalone Activity (Experimental)" + if hasHighlighting { + s.Command.Long = "Display information about a Standalone Activity.\n\n\x1b[1mtemporal activity describe \\\n --activity-id YourActivityId\x1b[0m" + } else { + s.Command.Long = "Display information about a Standalone Activity.\n\n```\ntemporal activity describe \\\n --activity-id YourActivityId\n```" + } + s.Command.Args = cobra.NoArgs + s.Command.Flags().BoolVar(&s.Raw, "raw", false, "Print properties without changing their format.") + s.ActivityReferenceOptions.BuildFlags(s.Command.Flags()) + s.Command.Run = func(c *cobra.Command, args []string) { + if err := s.run(cctx, args); err != nil { + cctx.Options.Fail(err) + } + } + return &s +} + +type TemporalActivityExecuteCommand struct { + Parent *TemporalActivityCommand + Command cobra.Command + ActivityStartOptions + PayloadInputOptions +} + +func NewTemporalActivityExecuteCommand(cctx *CommandContext, parent *TemporalActivityCommand) *TemporalActivityExecuteCommand { + var s TemporalActivityExecuteCommand + s.Parent = parent + s.Command.DisableFlagsInUseLine = true + s.Command.Use = "execute [flags]" + s.Command.Short = "Start a new Standalone Activity and wait for its result (Experimental)" + if hasHighlighting { + s.Command.Long = "Start a new Standalone Activity and block until it completes.\nThe result is output to stdout.\n\n\x1b[1mtemporal activity execute \\\n --activity-id YourActivityId \\\n --type YourActivity \\\n --task-queue YourTaskQueue \\\n --start-to-close-timeout 30s \\\n --input '{\"some-key\": \"some-value\"}'\x1b[0m" + } else { + s.Command.Long = "Start a new Standalone Activity and block until it completes.\nThe result is output to stdout.\n\n```\ntemporal activity execute \\\n --activity-id YourActivityId \\\n --type YourActivity \\\n --task-queue YourTaskQueue \\\n --start-to-close-timeout 30s \\\n --input '{\"some-key\": \"some-value\"}'\n```" + } + s.Command.Args = cobra.NoArgs + s.ActivityStartOptions.BuildFlags(s.Command.Flags()) + s.PayloadInputOptions.BuildFlags(s.Command.Flags()) + s.Command.Run = func(c *cobra.Command, args []string) { + if err := s.run(cctx, args); err != nil { + cctx.Options.Fail(err) + } + } + return &s +} + +type TemporalActivityFailCommand struct { + Parent *TemporalActivityCommand + Command cobra.Command ActivityId string + WorkflowId string + RunId string Detail string Reason string } @@ -452,18 +645,50 @@ func NewTemporalActivityFailCommand(cctx *CommandContext, parent *TemporalActivi s.Parent = parent s.Command.DisableFlagsInUseLine = true s.Command.Use = "fail [flags]" - s.Command.Short = "Fail an Activity" + s.Command.Short = "Mark an Activity as completed unsuccessfully with an error" if hasHighlighting { - s.Command.Long = "Fail an Activity, marking it as having encountered an error. Specify the\nActivity and Workflow IDs:\n\n\x1b[1mtemporal activity fail \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId\x1b[0m" + s.Command.Long = "Fail an Activity, marking it as having encountered an error:\n\n\x1b[1mtemporal activity fail \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId\x1b[0m" } else { - s.Command.Long = "Fail an Activity, marking it as having encountered an error. Specify the\nActivity and Workflow IDs:\n\n```\ntemporal activity fail \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId\n```" + s.Command.Long = "Fail an Activity, marking it as having encountered an error:\n\n```\ntemporal activity fail \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId\n```" } s.Command.Args = cobra.NoArgs - s.Command.Flags().StringVar(&s.ActivityId, "activity-id", "", "Activity ID to fail. Required.") + s.Command.Flags().StringVarP(&s.ActivityId, "activity-id", "a", "", "Activity ID. This may be the ID of an Activity invoked by a Workflow, or of a Standalone Activity. Required.") _ = cobra.MarkFlagRequired(s.Command.Flags(), "activity-id") - s.Command.Flags().StringVar(&s.Detail, "detail", "", "Reason for failing the Activity (JSON).") - s.Command.Flags().StringVar(&s.Reason, "reason", "", "Reason for failing the Activity.") - s.WorkflowReferenceOptions.BuildFlags(s.Command.Flags()) + s.Command.Flags().StringVarP(&s.WorkflowId, "workflow-id", "w", "", "Workflow ID. Required for workflow Activities. Omit for Standalone Activities.") + s.Command.Flags().StringVarP(&s.RunId, "run-id", "r", "", "Run ID. For workflow Activities (when --workflow-id is provided), this is the Workflow Run ID. For Standalone Activities, this is the Activity Run ID.") + s.Command.Flags().StringVar(&s.Detail, "detail", "", "Failure detail (JSON). Attached as the failure details payload.") + s.Command.Flags().StringVar(&s.Reason, "reason", "", "Failure reason. Attached as the failure message.") + s.Command.Run = func(c *cobra.Command, args []string) { + if err := s.run(cctx, args); err != nil { + cctx.Options.Fail(err) + } + } + return &s +} + +type TemporalActivityListCommand struct { + Parent *TemporalActivityCommand + Command cobra.Command + Query string + Limit int + PageSize int +} + +func NewTemporalActivityListCommand(cctx *CommandContext, parent *TemporalActivityCommand) *TemporalActivityListCommand { + var s TemporalActivityListCommand + s.Parent = parent + s.Command.DisableFlagsInUseLine = true + s.Command.Use = "list [flags]" + s.Command.Short = "List Standalone Activities matching a query (Experimental)" + if hasHighlighting { + s.Command.Long = "List Standalone Activities. Use \x1b[1m--query\x1b[0m to filter results.\n\n\x1b[1mtemporal activity list \\\n --query 'ActivityType=\"YourActivity\"'\x1b[0m\n\nVisit https://docs.temporal.io/visibility to read more about\nSearch Attributes and queries." + } else { + s.Command.Long = "List Standalone Activities. Use `--query` to filter results.\n\n```\ntemporal activity list \\\n --query 'ActivityType=\"YourActivity\"'\n```\n\nVisit https://docs.temporal.io/visibility to read more about\nSearch Attributes and queries." + } + s.Command.Args = cobra.NoArgs + s.Command.Flags().StringVarP(&s.Query, "query", "q", "", "Query to filter the Activity Executions to list.") + s.Command.Flags().IntVar(&s.Limit, "limit", 0, "Maximum number of Activity Executions to display.") + s.Command.Flags().IntVar(&s.PageSize, "page-size", 0, "Maximum number of Activity Executions to fetch at a time from the server.") s.Command.Run = func(c *cobra.Command, args []string) { if err := s.run(cctx, args); err != nil { cctx.Options.Fail(err) @@ -488,9 +713,9 @@ func NewTemporalActivityPauseCommand(cctx *CommandContext, parent *TemporalActiv s.Command.Use = "pause [flags]" s.Command.Short = "Pause an Activity" if hasHighlighting { - s.Command.Long = "Pause an Activity.\n\nIf the Activity is not currently running (e.g. because it previously\nfailed), it will not be run again until it is unpaused.\n\nHowever, if the Activity is currently running, it will run until the next\ntime it fails, completes, or times out, at which point the pause will kick in.\n\nIf the Activity is on its last retry attempt and fails, the failure will\nbe returned to the caller, just as if the Activity had not been paused.\n\nActivities should be specified either by their Activity ID or Activity Type.\n\nFor example, specify the Activity and Workflow IDs like this:\n\n\x1b[1mtemporal activity pause \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId\x1b[0m\n\nTo later unpause the activity, see unpause. You may also want to\nreset the activity to unpause it while also starting it from the beginning." + s.Command.Long = "Pause an Activity. Not supported for Standalone Activities.\n\nIf the Activity is not currently running (e.g. because it previously\nfailed), it will not be run again until it is unpaused.\n\nHowever, if the Activity is currently running, it will run until the next\ntime it fails, completes, or times out, at which point the pause will kick in.\n\nIf the Activity is on its last retry attempt and fails, the failure will\nbe returned to the caller, just as if the Activity had not been paused.\n\nActivities should be specified either by their Activity ID or Activity Type.\n\nFor example, specify the Activity and Workflow IDs like this:\n\n\x1b[1mtemporal activity pause \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId\x1b[0m\n\nTo later unpause the activity, see unpause. You may also want to\nreset the activity to unpause it while also starting it from the beginning." } else { - s.Command.Long = "Pause an Activity.\n\nIf the Activity is not currently running (e.g. because it previously\nfailed), it will not be run again until it is unpaused.\n\nHowever, if the Activity is currently running, it will run until the next\ntime it fails, completes, or times out, at which point the pause will kick in.\n\nIf the Activity is on its last retry attempt and fails, the failure will\nbe returned to the caller, just as if the Activity had not been paused.\n\nActivities should be specified either by their Activity ID or Activity Type.\n\nFor example, specify the Activity and Workflow IDs like this:\n\n```\ntemporal activity pause \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId\n```\n\nTo later unpause the activity, see unpause. You may also want to\nreset the activity to unpause it while also starting it from the beginning." + s.Command.Long = "Pause an Activity. Not supported for Standalone Activities.\n\nIf the Activity is not currently running (e.g. because it previously\nfailed), it will not be run again until it is unpaused.\n\nHowever, if the Activity is currently running, it will run until the next\ntime it fails, completes, or times out, at which point the pause will kick in.\n\nIf the Activity is on its last retry attempt and fails, the failure will\nbe returned to the caller, just as if the Activity had not been paused.\n\nActivities should be specified either by their Activity ID or Activity Type.\n\nFor example, specify the Activity and Workflow IDs like this:\n\n```\ntemporal activity pause \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId\n```\n\nTo later unpause the activity, see unpause. You may also want to\nreset the activity to unpause it while also starting it from the beginning." } s.Command.Args = cobra.NoArgs s.Command.Flags().StringVarP(&s.ActivityId, "activity-id", "a", "", "The Activity ID to pause. Either `activity-id` or `activity-type` must be provided, but not both.") @@ -526,9 +751,9 @@ func NewTemporalActivityResetCommand(cctx *CommandContext, parent *TemporalActiv s.Command.Use = "reset [flags]" s.Command.Short = "Reset an Activity" if hasHighlighting { - s.Command.Long = "Reset an activity. This restarts the activity as if it were first being\nscheduled. That is, it will reset both the number of attempts and the\nactivity timeout, as well as, optionally, the\nheartbeat details.\n\nIf the activity may be executing (i.e. it has not yet timed out), the\nreset will take effect the next time it fails, heartbeats, or times out.\nIf is waiting for a retry (i.e. has failed or timed out), the reset\nwill apply immediately.\n\nIf the activity is already paused, it will be unpaused by default.\nYou can specify \x1b[1mkeep_paused\x1b[0m to prevent this.\n\nIf the activity is paused and the \x1b[1mkeep_paused\x1b[0m flag is not provided,\nit will be unpaused. If the activity is paused and \x1b[1mkeep_paused\x1b[0m flag\nis provided - it will stay paused.\n\nActivities can be specified by their Activity ID or Activity Type.\n\n### Resetting activities that heartbeat {#reset-heartbeats}\n\nActivities that heartbeat will receive a Canceled failure\nthe next time they heartbeat after a reset.\n\nIf, in your Activity, you need to do any cleanup when an Activity is\nreset, handle this error and then re-throw it when you've cleaned up.\n\nIf the \x1b[1mreset_heartbeats\x1b[0m flag is set, the heartbeat details will also be cleared.\n\nSpecify the Activity Type of ID and Workflow IDs:\n\n\x1b[1mtemporal activity reset \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId\n --keep-paused\n --reset-heartbeats\x1b[0m\n\nEither \x1b[1mactivity-id\x1b[0m, \x1b[1mactivity-type\x1b[0m, or \x1b[1m--match-all\x1b[0m must be specified.\n\nActivities can be reset in bulk with a visibility query list filter.\nFor example, if you want to reset activities of type Foo:\n\n\x1b[1mtemporal activity reset \\\n --query 'TemporalResetInfo=\"property:activityType=Foo\"'\x1b[0m" + s.Command.Long = "Reset an activity. Not supported for Standalone Activities.\nThis restarts the activity as if it were first being\nscheduled. That is, it will reset both the number of attempts and the\nactivity timeout, as well as, optionally, the\nheartbeat details.\n\nIf the activity may be executing (i.e. it has not yet timed out), the\nreset will take effect the next time it fails, heartbeats, or times out.\nIf is waiting for a retry (i.e. has failed or timed out), the reset\nwill apply immediately.\n\nIf the activity is already paused, it will be unpaused by default.\nYou can specify \x1b[1mkeep_paused\x1b[0m to prevent this.\n\nIf the activity is paused and the \x1b[1mkeep_paused\x1b[0m flag is not provided,\nit will be unpaused. If the activity is paused and \x1b[1mkeep_paused\x1b[0m flag\nis provided - it will stay paused.\n\nActivities can be specified by their Activity ID or Activity Type.\n\n### Resetting activities that heartbeat {#reset-heartbeats}\n\nActivities that heartbeat will receive a Canceled failure\nthe next time they heartbeat after a reset.\n\nIf, in your Activity, you need to do any cleanup when an Activity is\nreset, handle this error and then re-throw it when you've cleaned up.\n\nIf the \x1b[1mreset_heartbeats\x1b[0m flag is set, the heartbeat details will also be cleared.\n\nSpecify the Activity Type of ID and Workflow IDs:\n\n\x1b[1mtemporal activity reset \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId\n --keep-paused\n --reset-heartbeats\x1b[0m\n\nEither \x1b[1mactivity-id\x1b[0m, \x1b[1mactivity-type\x1b[0m, or \x1b[1m--match-all\x1b[0m must be specified.\n\nActivities can be reset in bulk with a visibility query list filter.\nFor example, if you want to reset activities of type Foo:\n\n\x1b[1mtemporal activity reset \\\n --query 'TemporalResetInfo=\"property:activityType=Foo\"'\x1b[0m" } else { - s.Command.Long = "Reset an activity. This restarts the activity as if it were first being\nscheduled. That is, it will reset both the number of attempts and the\nactivity timeout, as well as, optionally, the\nheartbeat details.\n\nIf the activity may be executing (i.e. it has not yet timed out), the\nreset will take effect the next time it fails, heartbeats, or times out.\nIf is waiting for a retry (i.e. has failed or timed out), the reset\nwill apply immediately.\n\nIf the activity is already paused, it will be unpaused by default.\nYou can specify `keep_paused` to prevent this.\n\nIf the activity is paused and the `keep_paused` flag is not provided,\nit will be unpaused. If the activity is paused and `keep_paused` flag\nis provided - it will stay paused.\n\nActivities can be specified by their Activity ID or Activity Type.\n\n### Resetting activities that heartbeat {#reset-heartbeats}\n\nActivities that heartbeat will receive a Canceled failure\nthe next time they heartbeat after a reset.\n\nIf, in your Activity, you need to do any cleanup when an Activity is\nreset, handle this error and then re-throw it when you've cleaned up.\n\nIf the `reset_heartbeats` flag is set, the heartbeat details will also be cleared.\n\nSpecify the Activity Type of ID and Workflow IDs:\n\n```\ntemporal activity reset \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId\n --keep-paused\n --reset-heartbeats\n```\n\nEither `activity-id`, `activity-type`, or `--match-all` must be specified.\n\nActivities can be reset in bulk with a visibility query list filter.\nFor example, if you want to reset activities of type Foo:\n\n```\ntemporal activity reset \\\n --query 'TemporalResetInfo=\"property:activityType=Foo\"'\n```" + s.Command.Long = "Reset an activity. Not supported for Standalone Activities.\nThis restarts the activity as if it were first being\nscheduled. That is, it will reset both the number of attempts and the\nactivity timeout, as well as, optionally, the\nheartbeat details.\n\nIf the activity may be executing (i.e. it has not yet timed out), the\nreset will take effect the next time it fails, heartbeats, or times out.\nIf is waiting for a retry (i.e. has failed or timed out), the reset\nwill apply immediately.\n\nIf the activity is already paused, it will be unpaused by default.\nYou can specify `keep_paused` to prevent this.\n\nIf the activity is paused and the `keep_paused` flag is not provided,\nit will be unpaused. If the activity is paused and `keep_paused` flag\nis provided - it will stay paused.\n\nActivities can be specified by their Activity ID or Activity Type.\n\n### Resetting activities that heartbeat {#reset-heartbeats}\n\nActivities that heartbeat will receive a Canceled failure\nthe next time they heartbeat after a reset.\n\nIf, in your Activity, you need to do any cleanup when an Activity is\nreset, handle this error and then re-throw it when you've cleaned up.\n\nIf the `reset_heartbeats` flag is set, the heartbeat details will also be cleared.\n\nSpecify the Activity Type of ID and Workflow IDs:\n\n```\ntemporal activity reset \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId\n --keep-paused\n --reset-heartbeats\n```\n\nEither `activity-id`, `activity-type`, or `--match-all` must be specified.\n\nActivities can be reset in bulk with a visibility query list filter.\nFor example, if you want to reset activities of type Foo:\n\n```\ntemporal activity reset \\\n --query 'TemporalResetInfo=\"property:activityType=Foo\"'\n```" } s.Command.Args = cobra.NoArgs s.Command.Flags().StringVarP(&s.ActivityId, "activity-id", "a", "", "The Activity ID to reset. Mutually exclusive with `--query`, `--match-all`, and `--activity-type`. Requires `--workflow-id` to be specified.") @@ -549,6 +774,91 @@ func NewTemporalActivityResetCommand(cctx *CommandContext, parent *TemporalActiv return &s } +type TemporalActivityResultCommand struct { + Parent *TemporalActivityCommand + Command cobra.Command + ActivityReferenceOptions +} + +func NewTemporalActivityResultCommand(cctx *CommandContext, parent *TemporalActivityCommand) *TemporalActivityResultCommand { + var s TemporalActivityResultCommand + s.Parent = parent + s.Command.DisableFlagsInUseLine = true + s.Command.Use = "result [flags]" + s.Command.Short = "Wait for and output the result of a Standalone Activity (Experimental)" + if hasHighlighting { + s.Command.Long = "Wait for a Standalone Activity to complete and output the\nresult.\n\n\x1b[1mtemporal activity result \\\n --activity-id YourActivityId\x1b[0m" + } else { + s.Command.Long = "Wait for a Standalone Activity to complete and output the\nresult.\n\n```\ntemporal activity result \\\n --activity-id YourActivityId\n```" + } + s.Command.Args = cobra.NoArgs + s.ActivityReferenceOptions.BuildFlags(s.Command.Flags()) + s.Command.Run = func(c *cobra.Command, args []string) { + if err := s.run(cctx, args); err != nil { + cctx.Options.Fail(err) + } + } + return &s +} + +type TemporalActivityStartCommand struct { + Parent *TemporalActivityCommand + Command cobra.Command + ActivityStartOptions + PayloadInputOptions +} + +func NewTemporalActivityStartCommand(cctx *CommandContext, parent *TemporalActivityCommand) *TemporalActivityStartCommand { + var s TemporalActivityStartCommand + s.Parent = parent + s.Command.DisableFlagsInUseLine = true + s.Command.Use = "start [flags]" + s.Command.Short = "Start a new Standalone Activity (Experimental)" + if hasHighlighting { + s.Command.Long = "Start a new Standalone Activity. Outputs the Activity ID and\nRun ID.\n\n\x1b[1mtemporal activity start \\\n --activity-id YourActivityId \\\n --type YourActivity \\\n --task-queue YourTaskQueue \\\n --schedule-to-close-timeout 5m \\\n --input '{\"some-key\": \"some-value\"}'\x1b[0m" + } else { + s.Command.Long = "Start a new Standalone Activity. Outputs the Activity ID and\nRun ID.\n\n```\ntemporal activity start \\\n --activity-id YourActivityId \\\n --type YourActivity \\\n --task-queue YourTaskQueue \\\n --schedule-to-close-timeout 5m \\\n --input '{\"some-key\": \"some-value\"}'\n```" + } + s.Command.Args = cobra.NoArgs + s.ActivityStartOptions.BuildFlags(s.Command.Flags()) + s.PayloadInputOptions.BuildFlags(s.Command.Flags()) + s.Command.Run = func(c *cobra.Command, args []string) { + if err := s.run(cctx, args); err != nil { + cctx.Options.Fail(err) + } + } + return &s +} + +type TemporalActivityTerminateCommand struct { + Parent *TemporalActivityCommand + Command cobra.Command + ActivityReferenceOptions + Reason string +} + +func NewTemporalActivityTerminateCommand(cctx *CommandContext, parent *TemporalActivityCommand) *TemporalActivityTerminateCommand { + var s TemporalActivityTerminateCommand + s.Parent = parent + s.Command.DisableFlagsInUseLine = true + s.Command.Use = "terminate [flags]" + s.Command.Short = "Forcefully end a Standalone Activity (Experimental)" + if hasHighlighting { + s.Command.Long = "Terminate a Standalone Activity.\n\n\x1b[1mtemporal activity terminate \\\n --activity-id YourActivityId \\\n --reason YourReason\x1b[0m\n\nActivity code cannot see or respond to terminations." + } else { + s.Command.Long = "Terminate a Standalone Activity.\n\n```\ntemporal activity terminate \\\n --activity-id YourActivityId \\\n --reason YourReason\n```\n\nActivity code cannot see or respond to terminations." + } + s.Command.Args = cobra.NoArgs + s.Command.Flags().StringVar(&s.Reason, "reason", "", "Reason for termination. Defaults to a message with the current user's name.") + s.ActivityReferenceOptions.BuildFlags(s.Command.Flags()) + s.Command.Run = func(c *cobra.Command, args []string) { + if err := s.run(cctx, args); err != nil { + cctx.Options.Fail(err) + } + } + return &s +} + type TemporalActivityUnpauseCommand struct { Parent *TemporalActivityCommand Command cobra.Command @@ -568,9 +878,9 @@ func NewTemporalActivityUnpauseCommand(cctx *CommandContext, parent *TemporalAct s.Command.Use = "unpause [flags]" s.Command.Short = "Unpause an Activity" if hasHighlighting { - s.Command.Long = "Re-schedule a previously-paused Activity for execution.\n\nIf the Activity is not running and is past its retry timeout, it will be\nscheduled immediately. Otherwise, it will be scheduled after its retry\ntimeout expires.\n\nUse \x1b[1m--reset-attempts\x1b[0m to reset the number of previous run attempts to\nzero. For example, if an Activity is near the maximum number of attempts\nN specified in its retry policy, \x1b[1m--reset-attempts\x1b[0m will allow the\nActivity to be retried another N times after unpausing.\n\nUse \x1b[1m--reset-heartbeat\x1b[0m to reset the Activity's heartbeats.\n\nActivities can be specified by their Activity ID or Activity Type.\nOne of those parameters must be provided.\n\nSpecify the Activity ID or Type and Workflow IDs:\n\n\x1b[1mtemporal activity unpause \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId\n --reset-attempts\n --reset-heartbeats\x1b[0m\n\nActivities can be unpaused in bulk via a visibility Query list filter.\nFor example, if you want to unpause activities of type Foo that you\npreviously paused, do:\n\n\x1b[1mtemporal activity unpause \\\n --query 'TemporalPauseInfo=\"property:activityType=Foo\"'\x1b[0m" + s.Command.Long = "Re-schedule a previously-paused Activity for execution.\nNot supported for Standalone Activities.\n\nIf the Activity is not running and is past its retry timeout, it will be\nscheduled immediately. Otherwise, it will be scheduled after its retry\ntimeout expires.\n\nUse \x1b[1m--reset-attempts\x1b[0m to reset the number of previous run attempts to\nzero. For example, if an Activity is near the maximum number of attempts\nN specified in its retry policy, \x1b[1m--reset-attempts\x1b[0m will allow the\nActivity to be retried another N times after unpausing.\n\nUse \x1b[1m--reset-heartbeat\x1b[0m to reset the Activity's heartbeats.\n\nActivities can be specified by their Activity ID or Activity Type.\nOne of those parameters must be provided.\n\nSpecify the Activity ID or Type and Workflow IDs:\n\n\x1b[1mtemporal activity unpause \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId\n --reset-attempts\n --reset-heartbeats\x1b[0m\n\nActivities can be unpaused in bulk via a visibility Query list filter.\nFor example, if you want to unpause activities of type Foo that you\npreviously paused, do:\n\n\x1b[1mtemporal activity unpause \\\n --query 'TemporalPauseInfo=\"property:activityType=Foo\"'\x1b[0m" } else { - s.Command.Long = "Re-schedule a previously-paused Activity for execution.\n\nIf the Activity is not running and is past its retry timeout, it will be\nscheduled immediately. Otherwise, it will be scheduled after its retry\ntimeout expires.\n\nUse `--reset-attempts` to reset the number of previous run attempts to\nzero. For example, if an Activity is near the maximum number of attempts\nN specified in its retry policy, `--reset-attempts` will allow the\nActivity to be retried another N times after unpausing.\n\nUse `--reset-heartbeat` to reset the Activity's heartbeats.\n\nActivities can be specified by their Activity ID or Activity Type.\nOne of those parameters must be provided.\n\nSpecify the Activity ID or Type and Workflow IDs:\n\n```\ntemporal activity unpause \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId\n --reset-attempts\n --reset-heartbeats\n```\n\nActivities can be unpaused in bulk via a visibility Query list filter.\nFor example, if you want to unpause activities of type Foo that you\npreviously paused, do:\n\n```\ntemporal activity unpause \\\n --query 'TemporalPauseInfo=\"property:activityType=Foo\"'\n```" + s.Command.Long = "Re-schedule a previously-paused Activity for execution.\nNot supported for Standalone Activities.\n\nIf the Activity is not running and is past its retry timeout, it will be\nscheduled immediately. Otherwise, it will be scheduled after its retry\ntimeout expires.\n\nUse `--reset-attempts` to reset the number of previous run attempts to\nzero. For example, if an Activity is near the maximum number of attempts\nN specified in its retry policy, `--reset-attempts` will allow the\nActivity to be retried another N times after unpausing.\n\nUse `--reset-heartbeat` to reset the Activity's heartbeats.\n\nActivities can be specified by their Activity ID or Activity Type.\nOne of those parameters must be provided.\n\nSpecify the Activity ID or Type and Workflow IDs:\n\n```\ntemporal activity unpause \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId\n --reset-attempts\n --reset-heartbeats\n```\n\nActivities can be unpaused in bulk via a visibility Query list filter.\nFor example, if you want to unpause activities of type Foo that you\npreviously paused, do:\n\n```\ntemporal activity unpause \\\n --query 'TemporalPauseInfo=\"property:activityType=Foo\"'\n```" } s.Command.Args = cobra.NoArgs s.Command.Flags().StringVarP(&s.ActivityId, "activity-id", "a", "", "The Activity ID to unpause. Mutually exclusive with `--query`, `--match-all`, and `--activity-type`. Requires `--workflow-id` to be specified.") @@ -613,11 +923,11 @@ func NewTemporalActivityUpdateOptionsCommand(cctx *CommandContext, parent *Tempo s.Parent = parent s.Command.DisableFlagsInUseLine = true s.Command.Use = "update-options [flags]" - s.Command.Short = "Update Activity options" + s.Command.Short = "Change the values of options affecting a running Activity" if hasHighlighting { - s.Command.Long = "Update the options of a running Activity that were passed into it from\na Workflow. Updates are incremental, only changing the specified options.\n\nFor example:\n\n\x1b[1mtemporal activity update-options \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId \\\n --task-queue NewTaskQueueName \\\n --schedule-to-close-timeout DURATION \\\n --schedule-to-start-timeout DURATION \\\n --start-to-close-timeout DURATION \\\n --heartbeat-timeout DURATION \\\n --retry-initial-interval DURATION \\\n --retry-maximum-interval DURATION \\\n --retry-backoff-coefficient NewBackoffCoefficient \\\n --retry-maximum-attempts NewMaximumAttempts\x1b[0m\n\nYou may follow this command with \x1b[1mtemporal activity reset\x1b[0m, and the new values will apply after the reset.\n\nEither \x1b[1mactivity-id\x1b[0m, \x1b[1mactivity-type\x1b[0m, or \x1b[1m--match-all\x1b[0m must be specified.\n\nActivity options can be updated in bulk with a visibility query list filter.\nFor example, if you want to reset for activities of type Foo, do:\n\n\x1b[1mtemporal activity update-options \\\n --query 'TemporalPauseInfo=\"property:activityType=Foo\"'\n ...\x1b[0m" + s.Command.Long = "Update the options of a running Activity that were passed into it from\na Workflow. Updates are incremental, only changing the specified options.\nNot supported for Standalone Activities.\n\nFor example:\n\n\x1b[1mtemporal activity update-options \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId \\\n --task-queue NewTaskQueueName \\\n --schedule-to-close-timeout DURATION \\\n --schedule-to-start-timeout DURATION \\\n --start-to-close-timeout DURATION \\\n --heartbeat-timeout DURATION \\\n --retry-initial-interval DURATION \\\n --retry-maximum-interval DURATION \\\n --retry-backoff-coefficient NewBackoffCoefficient \\\n --retry-maximum-attempts NewMaximumAttempts\x1b[0m\n\nYou may follow this command with \x1b[1mtemporal activity reset\x1b[0m, and the new values will apply after the reset.\n\nEither \x1b[1mactivity-id\x1b[0m, \x1b[1mactivity-type\x1b[0m, or \x1b[1m--match-all\x1b[0m must be specified.\n\nActivity options can be updated in bulk with a visibility query list filter.\nFor example, if you want to reset for activities of type Foo, do:\n\n\x1b[1mtemporal activity update-options \\\n --query 'TemporalPauseInfo=\"property:activityType=Foo\"'\n ...\x1b[0m" } else { - s.Command.Long = "Update the options of a running Activity that were passed into it from\na Workflow. Updates are incremental, only changing the specified options.\n\nFor example:\n\n```\ntemporal activity update-options \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId \\\n --task-queue NewTaskQueueName \\\n --schedule-to-close-timeout DURATION \\\n --schedule-to-start-timeout DURATION \\\n --start-to-close-timeout DURATION \\\n --heartbeat-timeout DURATION \\\n --retry-initial-interval DURATION \\\n --retry-maximum-interval DURATION \\\n --retry-backoff-coefficient NewBackoffCoefficient \\\n --retry-maximum-attempts NewMaximumAttempts\n```\n\nYou may follow this command with `temporal activity reset`, and the new values will apply after the reset.\n\nEither `activity-id`, `activity-type`, or `--match-all` must be specified.\n\nActivity options can be updated in bulk with a visibility query list filter.\nFor example, if you want to reset for activities of type Foo, do:\n\n```\ntemporal activity update-options \\\n --query 'TemporalPauseInfo=\"property:activityType=Foo\"'\n ...\n```" + s.Command.Long = "Update the options of a running Activity that were passed into it from\na Workflow. Updates are incremental, only changing the specified options.\nNot supported for Standalone Activities.\n\nFor example:\n\n```\ntemporal activity update-options \\\n --activity-id YourActivityId \\\n --workflow-id YourWorkflowId \\\n --task-queue NewTaskQueueName \\\n --schedule-to-close-timeout DURATION \\\n --schedule-to-start-timeout DURATION \\\n --start-to-close-timeout DURATION \\\n --heartbeat-timeout DURATION \\\n --retry-initial-interval DURATION \\\n --retry-maximum-interval DURATION \\\n --retry-backoff-coefficient NewBackoffCoefficient \\\n --retry-maximum-attempts NewMaximumAttempts\n```\n\nYou may follow this command with `temporal activity reset`, and the new values will apply after the reset.\n\nEither `activity-id`, `activity-type`, or `--match-all` must be specified.\n\nActivity options can be updated in bulk with a visibility query list filter.\nFor example, if you want to reset for activities of type Foo, do:\n\n```\ntemporal activity update-options \\\n --query 'TemporalPauseInfo=\"property:activityType=Foo\"'\n ...\n```" } s.Command.Args = cobra.NoArgs s.Command.Flags().StringVarP(&s.ActivityId, "activity-id", "a", "", "The Activity ID to update options. Mutually exclusive with `--query`, `--match-all`, and `--activity-type`. Requires `--workflow-id` to be specified.") @@ -2273,9 +2583,9 @@ func NewTemporalTaskQueueDescribeCommand(cctx *CommandContext, parent *TemporalT s.Command.Use = "describe [flags]" s.Command.Short = "Show active Workers" if hasHighlighting { - s.Command.Long = "Display a list of active Workers that have recently polled a Task Queue. The\nTemporal Server records each poll request time. A \x1b[1mLastAccessTime\x1b[0m over one\nminute may indicate the Worker is at capacity or has shut down. Temporal\nWorkers are removed if 5 minutes have passed since the last poll request.\n\n\x1b[1mtemporal task-queue describe \\\n --task-queue YourTaskQueue\x1b[0m\n\nThis command provides poller information for a given Task Queue.\nWorkflow and Activity polling use separate Task Queues:\n\n\x1b[1mtemporal task-queue describe \\\n --task-queue YourTaskQueue \\\n --task-queue-type \"activity\"\x1b[0m\n\nThis command provides the following task queue statistics:\n- \x1b[1mApproximateBacklogCount\x1b[0m: The approximate number of tasks backlogged in this\n task queue. May count expired tasks but eventually converges to the right\n value.\n- \x1b[1mApproximateBacklogAge\x1b[0m: Approximate age of the oldest task in the backlog,\n based on its creation time, measured in seconds.\n- \x1b[1mTasksAddRate\x1b[0m: Approximate rate at which tasks are being added to the task\n queue, measured in tasks per second, averaged over the last 30 seconds.\n Includes tasks dispatched immediately without going to the backlog\n (sync-matched tasks), as well as tasks added to the backlog. (See note below.)\n- \x1b[1mTasksDispatchRate\x1b[0m: Approximate rate at which tasks are being dispatched from\n the task queue, measured in tasks per second, averaged over the last 30\n seconds. Includes tasks dispatched immediately without going to the backlog\n (sync-matched tasks), as well as tasks added to the backlog. (See note below.)\n- \x1b[1mBacklogIncreaseRate\x1b[0m: Approximate rate at which the backlog size is\n increasing (if positive) or decreasing (if negative), measured in tasks per\n second, averaged over the last 30 seconds. This is roughly equivalent to:\n \x1b[1mTasksAddRate\x1b[0m - \x1b[1mTasksDispatchRate\x1b[0m.\n\nNOTE: The \x1b[1mTasksAddRate\x1b[0m and \x1b[1mTasksDispatchRate\x1b[0m metrics may differ from the\nactual rate of add/dispatch, because tasks may be dispatched eagerly to an\navailable worker, or may apply only to specific workers (they are \"sticky\").\nSuch tasks are not counted by these metrics. Despite the inaccuracy of\nthese two metrics, the derived metric of \x1b[1mBacklogIncreaseRate\x1b[0m is accurate\nfor backlogs older than a few seconds.\n\nSafely retire Workers assigned a Build ID by checking reachability across\nall task types. Use the flag \x1b[1m--report-reachability\x1b[0m:\n\n\x1b[1mtemporal task-queue describe \\\n --task-queue YourTaskQueue \\\n --select-build-id \"YourBuildId\" \\\n --report-reachability\x1b[0m\n\nTask reachability information is returned for the requested versions and all\ntask types, which can be used to safely retire Workers with old code versions,\nprovided that they were assigned a Build ID.\n\nNote that task reachability status is deprecated in favor of Drainage Status\n(ie. of a Drained or Draining Worker Deployment Version) and will be removed \nin a future release. Also, determining task reachability incurs a non-trivial \ncomputing cost.\n\nTask reachability states are reported per build ID. The state may be one of the\nfollowing:\n\n- \x1b[1mReachable\x1b[0m: using the current versioning rules, the Build ID may be used\n by new Workflow Executions or Activities OR there are currently open\n Workflow or backlogged Activity tasks assigned to the queue.\n- \x1b[1mClosedWorkflowsOnly\x1b[0m: the Build ID does not have open Workflow Executions\n and can't be reached by new Workflow Executions. It MAY have closed\n Workflow Executions within the Namespace retention period.\n- \x1b[1mUnreachable\x1b[0m: this Build ID is not used for new Workflow Executions and\n isn't used by any existing Workflow Execution within the retention period.\n\nTask reachability is eventually consistent. You may experience a delay until\nreachability converges to the most accurate value. This is designed to act\nin the most conservative way until convergence. For example, \x1b[1mReachable\x1b[0m is\nmore conservative than \x1b[1mClosedWorkflowsOnly\x1b[0m." + s.Command.Long = "Display a list of active Workers that have recently polled a Task Queue. The\nTemporal Server records each poll request time. A \x1b[1mLastAccessTime\x1b[0m over one\nminute may indicate the Worker is at capacity or has shut down. Temporal\nWorkers are removed if 5 minutes have passed since the last poll request.\n\n\x1b[1mtemporal task-queue describe \\\n --task-queue YourTaskQueue\x1b[0m\n\nThis command provides poller information for a given Task Queue.\nWorkflow and Activity polling use separate Task Queues:\n\n\x1b[1mtemporal task-queue describe \\\n --task-queue YourTaskQueue \\\n --task-queue-type \"activity\"\x1b[0m\n\nThis command provides the following task queue statistics:\n- \x1b[1mApproximateBacklogCount\x1b[0m: The approximate number of tasks backlogged in this\n task queue. May count expired tasks but eventually converges to the right\n value.\n- \x1b[1mApproximateBacklogAge\x1b[0m: Approximate age of the oldest task in the backlog,\n based on its creation time, measured in seconds.\n- \x1b[1mTasksAddRate\x1b[0m: Approximate rate at which tasks are being added to the task\n queue, measured in tasks per second, averaged over the last 30 seconds.\n Includes tasks dispatched immediately without going to the backlog\n (sync-matched tasks), as well as tasks added to the backlog. (See note below.)\n- \x1b[1mTasksDispatchRate\x1b[0m: Approximate rate at which tasks are being dispatched from\n the task queue, measured in tasks per second, averaged over the last 30\n seconds. Includes tasks dispatched immediately without going to the backlog\n (sync-matched tasks), as well as tasks added to the backlog. (See note below.)\n- \x1b[1mBacklogIncreaseRate\x1b[0m: Approximate rate at which the backlog size is\n increasing (if positive) or decreasing (if negative), measured in tasks per\n second, averaged over the last 30 seconds. This is roughly equivalent to:\n \x1b[1mTasksAddRate\x1b[0m - \x1b[1mTasksDispatchRate\x1b[0m.\n\nNOTE: The \x1b[1mTasksAddRate\x1b[0m and \x1b[1mTasksDispatchRate\x1b[0m metrics may differ from the\nactual rate of add/dispatch, because tasks may be dispatched eagerly to an\navailable worker, or may apply only to specific workers (they are \"sticky\").\nSuch tasks are not counted by these metrics. Despite the inaccuracy of\nthese two metrics, the derived metric of \x1b[1mBacklogIncreaseRate\x1b[0m is accurate\nfor backlogs older than a few seconds.\n\nSafely retire Workers assigned a Build ID by checking reachability across\nall task types. Use the flag \x1b[1m--report-reachability\x1b[0m:\n\n\x1b[1mtemporal task-queue describe \\\n --task-queue YourTaskQueue \\\n --select-build-id \"YourBuildId\" \\\n --report-reachability\x1b[0m\n\nTask reachability information is returned for the requested versions and all\ntask types, which can be used to safely retire Workers with old code versions,\nprovided that they were assigned a Build ID.\n\nNote that task reachability status is deprecated in favor of Drainage Status\n(ie. of a Drained or Draining Worker Deployment Version) and will be removed\nin a future release. Also, determining task reachability incurs a non-trivial\ncomputing cost.\n\nTask reachability states are reported per build ID. The state may be one of the\nfollowing:\n\n- \x1b[1mReachable\x1b[0m: using the current versioning rules, the Build ID may be used\n by new Workflow Executions or Activities OR there are currently open\n Workflow or backlogged Activity tasks assigned to the queue.\n- \x1b[1mClosedWorkflowsOnly\x1b[0m: the Build ID does not have open Workflow Executions\n and can't be reached by new Workflow Executions. It MAY have closed\n Workflow Executions within the Namespace retention period.\n- \x1b[1mUnreachable\x1b[0m: this Build ID is not used for new Workflow Executions and\n isn't used by any existing Workflow Execution within the retention period.\n\nTask reachability is eventually consistent. You may experience a delay until\nreachability converges to the most accurate value. This is designed to act\nin the most conservative way until convergence. For example, \x1b[1mReachable\x1b[0m is\nmore conservative than \x1b[1mClosedWorkflowsOnly\x1b[0m." } else { - s.Command.Long = "Display a list of active Workers that have recently polled a Task Queue. The\nTemporal Server records each poll request time. A `LastAccessTime` over one\nminute may indicate the Worker is at capacity or has shut down. Temporal\nWorkers are removed if 5 minutes have passed since the last poll request.\n\n```\ntemporal task-queue describe \\\n --task-queue YourTaskQueue\n```\n\nThis command provides poller information for a given Task Queue.\nWorkflow and Activity polling use separate Task Queues:\n\n```\ntemporal task-queue describe \\\n --task-queue YourTaskQueue \\\n --task-queue-type \"activity\"\n```\n\nThis command provides the following task queue statistics:\n- `ApproximateBacklogCount`: The approximate number of tasks backlogged in this\n task queue. May count expired tasks but eventually converges to the right\n value.\n- `ApproximateBacklogAge`: Approximate age of the oldest task in the backlog,\n based on its creation time, measured in seconds.\n- `TasksAddRate`: Approximate rate at which tasks are being added to the task\n queue, measured in tasks per second, averaged over the last 30 seconds.\n Includes tasks dispatched immediately without going to the backlog\n (sync-matched tasks), as well as tasks added to the backlog. (See note below.)\n- `TasksDispatchRate`: Approximate rate at which tasks are being dispatched from\n the task queue, measured in tasks per second, averaged over the last 30\n seconds. Includes tasks dispatched immediately without going to the backlog\n (sync-matched tasks), as well as tasks added to the backlog. (See note below.)\n- `BacklogIncreaseRate`: Approximate rate at which the backlog size is\n increasing (if positive) or decreasing (if negative), measured in tasks per\n second, averaged over the last 30 seconds. This is roughly equivalent to:\n `TasksAddRate` - `TasksDispatchRate`.\n\nNOTE: The `TasksAddRate` and `TasksDispatchRate` metrics may differ from the\nactual rate of add/dispatch, because tasks may be dispatched eagerly to an\navailable worker, or may apply only to specific workers (they are \"sticky\").\nSuch tasks are not counted by these metrics. Despite the inaccuracy of\nthese two metrics, the derived metric of `BacklogIncreaseRate` is accurate\nfor backlogs older than a few seconds.\n\nSafely retire Workers assigned a Build ID by checking reachability across\nall task types. Use the flag `--report-reachability`:\n\n```\ntemporal task-queue describe \\\n --task-queue YourTaskQueue \\\n --select-build-id \"YourBuildId\" \\\n --report-reachability\n```\n\nTask reachability information is returned for the requested versions and all\ntask types, which can be used to safely retire Workers with old code versions,\nprovided that they were assigned a Build ID.\n\nNote that task reachability status is deprecated in favor of Drainage Status\n(ie. of a Drained or Draining Worker Deployment Version) and will be removed \nin a future release. Also, determining task reachability incurs a non-trivial \ncomputing cost.\n\nTask reachability states are reported per build ID. The state may be one of the\nfollowing:\n\n- `Reachable`: using the current versioning rules, the Build ID may be used\n by new Workflow Executions or Activities OR there are currently open\n Workflow or backlogged Activity tasks assigned to the queue.\n- `ClosedWorkflowsOnly`: the Build ID does not have open Workflow Executions\n and can't be reached by new Workflow Executions. It MAY have closed\n Workflow Executions within the Namespace retention period.\n- `Unreachable`: this Build ID is not used for new Workflow Executions and\n isn't used by any existing Workflow Execution within the retention period.\n\nTask reachability is eventually consistent. You may experience a delay until\nreachability converges to the most accurate value. This is designed to act\nin the most conservative way until convergence. For example, `Reachable` is\nmore conservative than `ClosedWorkflowsOnly`." + s.Command.Long = "Display a list of active Workers that have recently polled a Task Queue. The\nTemporal Server records each poll request time. A `LastAccessTime` over one\nminute may indicate the Worker is at capacity or has shut down. Temporal\nWorkers are removed if 5 minutes have passed since the last poll request.\n\n```\ntemporal task-queue describe \\\n --task-queue YourTaskQueue\n```\n\nThis command provides poller information for a given Task Queue.\nWorkflow and Activity polling use separate Task Queues:\n\n```\ntemporal task-queue describe \\\n --task-queue YourTaskQueue \\\n --task-queue-type \"activity\"\n```\n\nThis command provides the following task queue statistics:\n- `ApproximateBacklogCount`: The approximate number of tasks backlogged in this\n task queue. May count expired tasks but eventually converges to the right\n value.\n- `ApproximateBacklogAge`: Approximate age of the oldest task in the backlog,\n based on its creation time, measured in seconds.\n- `TasksAddRate`: Approximate rate at which tasks are being added to the task\n queue, measured in tasks per second, averaged over the last 30 seconds.\n Includes tasks dispatched immediately without going to the backlog\n (sync-matched tasks), as well as tasks added to the backlog. (See note below.)\n- `TasksDispatchRate`: Approximate rate at which tasks are being dispatched from\n the task queue, measured in tasks per second, averaged over the last 30\n seconds. Includes tasks dispatched immediately without going to the backlog\n (sync-matched tasks), as well as tasks added to the backlog. (See note below.)\n- `BacklogIncreaseRate`: Approximate rate at which the backlog size is\n increasing (if positive) or decreasing (if negative), measured in tasks per\n second, averaged over the last 30 seconds. This is roughly equivalent to:\n `TasksAddRate` - `TasksDispatchRate`.\n\nNOTE: The `TasksAddRate` and `TasksDispatchRate` metrics may differ from the\nactual rate of add/dispatch, because tasks may be dispatched eagerly to an\navailable worker, or may apply only to specific workers (they are \"sticky\").\nSuch tasks are not counted by these metrics. Despite the inaccuracy of\nthese two metrics, the derived metric of `BacklogIncreaseRate` is accurate\nfor backlogs older than a few seconds.\n\nSafely retire Workers assigned a Build ID by checking reachability across\nall task types. Use the flag `--report-reachability`:\n\n```\ntemporal task-queue describe \\\n --task-queue YourTaskQueue \\\n --select-build-id \"YourBuildId\" \\\n --report-reachability\n```\n\nTask reachability information is returned for the requested versions and all\ntask types, which can be used to safely retire Workers with old code versions,\nprovided that they were assigned a Build ID.\n\nNote that task reachability status is deprecated in favor of Drainage Status\n(ie. of a Drained or Draining Worker Deployment Version) and will be removed\nin a future release. Also, determining task reachability incurs a non-trivial\ncomputing cost.\n\nTask reachability states are reported per build ID. The state may be one of the\nfollowing:\n\n- `Reachable`: using the current versioning rules, the Build ID may be used\n by new Workflow Executions or Activities OR there are currently open\n Workflow or backlogged Activity tasks assigned to the queue.\n- `ClosedWorkflowsOnly`: the Build ID does not have open Workflow Executions\n and can't be reached by new Workflow Executions. It MAY have closed\n Workflow Executions within the Namespace retention period.\n- `Unreachable`: this Build ID is not used for new Workflow Executions and\n isn't used by any existing Workflow Execution within the retention period.\n\nTask reachability is eventually consistent. You may experience a delay until\nreachability converges to the most accurate value. This is designed to act\nin the most conservative way until convergence. For example, `Reachable` is\nmore conservative than `ClosedWorkflowsOnly`." } s.Command.Args = cobra.NoArgs s.Command.Flags().StringVarP(&s.TaskQueue, "task-queue", "t", "", "Task Queue name. Required.") @@ -3028,9 +3338,9 @@ func NewTemporalWorkerDeploymentManagerIdentityCommand(cctx *CommandContext, par s.Command.Use = "manager-identity" s.Command.Short = "Manager Identity commands change the `ManagerIdentity` of a Worker Deployment" if hasHighlighting { - s.Command.Long = "Manager Identity commands change the \x1b[1mManagerIdentity\x1b[0m of a Worker Deployment:\n\n\x1b[1mtemporal worker deployment manager-identity [command] [options]\x1b[0m\n\nWhen present, \x1b[1mManagerIdentity\x1b[0m is the identity of the user that has the \nexclusive right to make changes to this Worker Deployment. Empty by default.\nWhen set, users whose identity does not match the \x1b[1mManagerIdentity\x1b[0m will not\nbe able to change the Worker Deployment.\n\nThis is especially useful in environments where multiple users (such as CLI\nusers and automated controllers) may interact with the same Worker Deployment.\n\x1b[1mManagerIdentity\x1b[0m allows different users to communicate with one another about\nwho is expected to make changes to the Worker Deployment.\n\nThe current Manager Identity is returned with \x1b[1mdescribe\x1b[0m:\n\x1b[1m temporal worker deployment describe \\\n --deployment-name YourDeploymentName\x1b[0m" + s.Command.Long = "Manager Identity commands change the \x1b[1mManagerIdentity\x1b[0m of a Worker Deployment:\n\n\x1b[1mtemporal worker deployment manager-identity [command] [options]\x1b[0m\n\nWhen present, \x1b[1mManagerIdentity\x1b[0m is the identity of the user that has the\nexclusive right to make changes to this Worker Deployment. Empty by default.\nWhen set, users whose identity does not match the \x1b[1mManagerIdentity\x1b[0m will not\nbe able to change the Worker Deployment.\n\nThis is especially useful in environments where multiple users (such as CLI\nusers and automated controllers) may interact with the same Worker Deployment.\n\x1b[1mManagerIdentity\x1b[0m allows different users to communicate with one another about\nwho is expected to make changes to the Worker Deployment.\n\nThe current Manager Identity is returned with \x1b[1mdescribe\x1b[0m:\n\x1b[1m temporal worker deployment describe \\\n --deployment-name YourDeploymentName\x1b[0m" } else { - s.Command.Long = "Manager Identity commands change the `ManagerIdentity` of a Worker Deployment:\n\n```\ntemporal worker deployment manager-identity [command] [options]\n```\n\nWhen present, `ManagerIdentity` is the identity of the user that has the \nexclusive right to make changes to this Worker Deployment. Empty by default.\nWhen set, users whose identity does not match the `ManagerIdentity` will not\nbe able to change the Worker Deployment.\n\nThis is especially useful in environments where multiple users (such as CLI\nusers and automated controllers) may interact with the same Worker Deployment.\n`ManagerIdentity` allows different users to communicate with one another about\nwho is expected to make changes to the Worker Deployment.\n\nThe current Manager Identity is returned with `describe`:\n```\n temporal worker deployment describe \\\n --deployment-name YourDeploymentName\n```" + s.Command.Long = "Manager Identity commands change the `ManagerIdentity` of a Worker Deployment:\n\n```\ntemporal worker deployment manager-identity [command] [options]\n```\n\nWhen present, `ManagerIdentity` is the identity of the user that has the\nexclusive right to make changes to this Worker Deployment. Empty by default.\nWhen set, users whose identity does not match the `ManagerIdentity` will not\nbe able to change the Worker Deployment.\n\nThis is especially useful in environments where multiple users (such as CLI\nusers and automated controllers) may interact with the same Worker Deployment.\n`ManagerIdentity` allows different users to communicate with one another about\nwho is expected to make changes to the Worker Deployment.\n\nThe current Manager Identity is returned with `describe`:\n```\n temporal worker deployment describe \\\n --deployment-name YourDeploymentName\n```" } s.Command.Args = cobra.NoArgs s.Command.AddCommand(&NewTemporalWorkerDeploymentManagerIdentitySetCommand(cctx, &s).Command) @@ -3054,9 +3364,9 @@ func NewTemporalWorkerDeploymentManagerIdentitySetCommand(cctx *CommandContext, s.Command.Use = "set [flags]" s.Command.Short = "Set the Manager Identity of a Worker Deployment" if hasHighlighting { - s.Command.Long = "Set the \x1b[1mManagerIdentity\x1b[0m of a Worker Deployment given its Deployment Name.\n\nWhen present, \x1b[1mManagerIdentity\x1b[0m is the identity of the user that has the \nexclusive right to make changes to this Worker Deployment. Empty by default.\nWhen set, users whose identity does not match the \x1b[1mManagerIdentity\x1b[0m will not\nbe able to change the Worker Deployment.\n\nThis is especially useful in environments where multiple users (such as CLI\nusers and automated controllers) may interact with the same Worker Deployment.\n\x1b[1mManagerIdentity\x1b[0m allows different users to communicate with one another about\nwho is expected to make changes to the Worker Deployment.\n\n\x1b[1mtemporal worker deployment manager-identity set [options]\x1b[0m\n\nFor example:\n\n\x1b[1mtemporal worker deployment manager-identity set \\\n --deployment-name DeploymentName \\\n --self \\\n --identity YourUserIdentity # optional, populated by CLI if not provided\x1b[0m\n\nSets the Manager Identity of the Deployment to the identity of the user making \nthis request. If you don't specifically pass an identity field, the CLI will \ngenerate your identity for you.\n\nFor example:\n\x1b[1mtemporal worker deployment manager-identity set \\\n --deployment-name DeploymentName \\\n --manager-identity NewManagerIdentity\x1b[0m\n\nSets the Manager Identity of the Deployment to any string." + s.Command.Long = "Set the \x1b[1mManagerIdentity\x1b[0m of a Worker Deployment given its Deployment Name.\n\nWhen present, \x1b[1mManagerIdentity\x1b[0m is the identity of the user that has the\nexclusive right to make changes to this Worker Deployment. Empty by default.\nWhen set, users whose identity does not match the \x1b[1mManagerIdentity\x1b[0m will not\nbe able to change the Worker Deployment.\n\nThis is especially useful in environments where multiple users (such as CLI\nusers and automated controllers) may interact with the same Worker Deployment.\n\x1b[1mManagerIdentity\x1b[0m allows different users to communicate with one another about\nwho is expected to make changes to the Worker Deployment.\n\n\x1b[1mtemporal worker deployment manager-identity set [options]\x1b[0m\n\nFor example:\n\n\x1b[1mtemporal worker deployment manager-identity set \\\n --deployment-name DeploymentName \\\n --self \\\n --identity YourUserIdentity # optional, populated by CLI if not provided\x1b[0m\n\nSets the Manager Identity of the Deployment to the identity of the user making\nthis request. If you don't specifically pass an identity field, the CLI will\ngenerate your identity for you.\n\nFor example:\n\x1b[1mtemporal worker deployment manager-identity set \\\n --deployment-name DeploymentName \\\n --manager-identity NewManagerIdentity\x1b[0m\n\nSets the Manager Identity of the Deployment to any string." } else { - s.Command.Long = "Set the `ManagerIdentity` of a Worker Deployment given its Deployment Name.\n\nWhen present, `ManagerIdentity` is the identity of the user that has the \nexclusive right to make changes to this Worker Deployment. Empty by default.\nWhen set, users whose identity does not match the `ManagerIdentity` will not\nbe able to change the Worker Deployment.\n\nThis is especially useful in environments where multiple users (such as CLI\nusers and automated controllers) may interact with the same Worker Deployment.\n`ManagerIdentity` allows different users to communicate with one another about\nwho is expected to make changes to the Worker Deployment.\n\n```\ntemporal worker deployment manager-identity set [options]\n```\n\nFor example:\n\n```\ntemporal worker deployment manager-identity set \\\n --deployment-name DeploymentName \\\n --self \\\n --identity YourUserIdentity # optional, populated by CLI if not provided\n```\n\nSets the Manager Identity of the Deployment to the identity of the user making \nthis request. If you don't specifically pass an identity field, the CLI will \ngenerate your identity for you.\n\nFor example:\n```\ntemporal worker deployment manager-identity set \\\n --deployment-name DeploymentName \\\n --manager-identity NewManagerIdentity\n```\n\nSets the Manager Identity of the Deployment to any string." + s.Command.Long = "Set the `ManagerIdentity` of a Worker Deployment given its Deployment Name.\n\nWhen present, `ManagerIdentity` is the identity of the user that has the\nexclusive right to make changes to this Worker Deployment. Empty by default.\nWhen set, users whose identity does not match the `ManagerIdentity` will not\nbe able to change the Worker Deployment.\n\nThis is especially useful in environments where multiple users (such as CLI\nusers and automated controllers) may interact with the same Worker Deployment.\n`ManagerIdentity` allows different users to communicate with one another about\nwho is expected to make changes to the Worker Deployment.\n\n```\ntemporal worker deployment manager-identity set [options]\n```\n\nFor example:\n\n```\ntemporal worker deployment manager-identity set \\\n --deployment-name DeploymentName \\\n --self \\\n --identity YourUserIdentity # optional, populated by CLI if not provided\n```\n\nSets the Manager Identity of the Deployment to the identity of the user making\nthis request. If you don't specifically pass an identity field, the CLI will\ngenerate your identity for you.\n\nFor example:\n```\ntemporal worker deployment manager-identity set \\\n --deployment-name DeploymentName \\\n --manager-identity NewManagerIdentity\n```\n\nSets the Manager Identity of the Deployment to any string." } s.Command.Args = cobra.NoArgs s.Command.Flags().StringVar(&s.ManagerIdentity, "manager-identity", "", "New Manager Identity. Required unless --self is specified.") @@ -3085,9 +3395,9 @@ func NewTemporalWorkerDeploymentManagerIdentityUnsetCommand(cctx *CommandContext s.Command.Use = "unset [flags]" s.Command.Short = "Unset the Manager Identity of a Worker Deployment" if hasHighlighting { - s.Command.Long = "Unset the \x1b[1mManagerIdentity\x1b[0m of a Worker Deployment given its Deployment Name.\n\nWhen present, \x1b[1mManagerIdentity\x1b[0m is the identity of the user that has the \nexclusive right to make changes to this Worker Deployment. Empty by default.\nWhen set, users whose identity does not match the \x1b[1mManagerIdentity\x1b[0m will not\nbe able to change the Worker Deployment.\n\nThis is especially useful in environments where multiple users (such as CLI\nusers and automated controllers) may interact with the same Worker Deployment.\n\x1b[1mManagerIdentity\x1b[0m allows different users to communicate with one another about\nwho is expected to make changes to the Worker Deployment.\n\n\x1b[1mtemporal worker deployment manager-identity unset [options]\x1b[0m\n\nFor example:\n\n\x1b[1mtemporal worker deployment manager-identity unset \\\n --deployment-name YourDeploymentName\x1b[0m\n\nClears the Manager Identity field for a given Deployment." + s.Command.Long = "Unset the \x1b[1mManagerIdentity\x1b[0m of a Worker Deployment given its Deployment Name.\n\nWhen present, \x1b[1mManagerIdentity\x1b[0m is the identity of the user that has the\nexclusive right to make changes to this Worker Deployment. Empty by default.\nWhen set, users whose identity does not match the \x1b[1mManagerIdentity\x1b[0m will not\nbe able to change the Worker Deployment.\n\nThis is especially useful in environments where multiple users (such as CLI\nusers and automated controllers) may interact with the same Worker Deployment.\n\x1b[1mManagerIdentity\x1b[0m allows different users to communicate with one another about\nwho is expected to make changes to the Worker Deployment.\n\n\x1b[1mtemporal worker deployment manager-identity unset [options]\x1b[0m\n\nFor example:\n\n\x1b[1mtemporal worker deployment manager-identity unset \\\n --deployment-name YourDeploymentName\x1b[0m\n\nClears the Manager Identity field for a given Deployment." } else { - s.Command.Long = "Unset the `ManagerIdentity` of a Worker Deployment given its Deployment Name.\n\nWhen present, `ManagerIdentity` is the identity of the user that has the \nexclusive right to make changes to this Worker Deployment. Empty by default.\nWhen set, users whose identity does not match the `ManagerIdentity` will not\nbe able to change the Worker Deployment.\n\nThis is especially useful in environments where multiple users (such as CLI\nusers and automated controllers) may interact with the same Worker Deployment.\n`ManagerIdentity` allows different users to communicate with one another about\nwho is expected to make changes to the Worker Deployment.\n\n```\ntemporal worker deployment manager-identity unset [options]\n```\n\nFor example:\n\n```\ntemporal worker deployment manager-identity unset \\\n --deployment-name YourDeploymentName\n```\n\nClears the Manager Identity field for a given Deployment." + s.Command.Long = "Unset the `ManagerIdentity` of a Worker Deployment given its Deployment Name.\n\nWhen present, `ManagerIdentity` is the identity of the user that has the\nexclusive right to make changes to this Worker Deployment. Empty by default.\nWhen set, users whose identity does not match the `ManagerIdentity` will not\nbe able to change the Worker Deployment.\n\nThis is especially useful in environments where multiple users (such as CLI\nusers and automated controllers) may interact with the same Worker Deployment.\n`ManagerIdentity` allows different users to communicate with one another about\nwho is expected to make changes to the Worker Deployment.\n\n```\ntemporal worker deployment manager-identity unset [options]\n```\n\nFor example:\n\n```\ntemporal worker deployment manager-identity unset \\\n --deployment-name YourDeploymentName\n```\n\nClears the Manager Identity field for a given Deployment." } s.Command.Args = cobra.NoArgs s.Command.Flags().StringVar(&s.DeploymentName, "deployment-name", "", "Name for a Worker Deployment. Required.") diff --git a/internal/temporalcli/commands.go b/internal/temporalcli/commands.go index a60307b83..a0df01905 100644 --- a/internal/temporalcli/commands.go +++ b/internal/temporalcli/commands.go @@ -234,6 +234,36 @@ func (c *CommandContext) MarshalFriendlyFailureBodyText(f *failure.Failure, inde return } +type countGroup interface { + GetGroupValues() []*commonpb.Payload + GetCount() int64 +} + +func printCountGroupsText(cctx *CommandContext, groups []countGroup) { + for _, group := range groups { + var valueStr string + for _, payload := range group.GetGroupValues() { + var value any + if err := converter.GetDefaultDataConverter().FromPayload(payload, &value); err != nil { + value = fmt.Sprintf("", err) + } + if valueStr != "" { + valueStr += ", " + } + valueStr += fmt.Sprintf("%v", value) + } + cctx.Printer.Printlnf("Group total: %v, values: %v", group.GetCount(), valueStr) + } +} + +func stripCountGroupMetadataType(groups []countGroup) { + for _, group := range groups { + for _, payload := range group.GetGroupValues() { + delete(payload.GetMetadata(), "type") + } + } +} + // Takes payload shorthand into account, can use // MarshalProtoJSONNoPayloadShorthand if needed func (c *CommandContext) MarshalProtoJSON(m proto.Message) ([]byte, error) { diff --git a/internal/temporalcli/commands.workflow_view.go b/internal/temporalcli/commands.workflow_view.go index 08fb5c76e..df7230da5 100644 --- a/internal/temporalcli/commands.workflow_view.go +++ b/internal/temporalcli/commands.workflow_view.go @@ -15,7 +15,7 @@ import ( "go.temporal.io/api/workflow/v1" "go.temporal.io/api/workflowservice/v1" "go.temporal.io/sdk/client" - "go.temporal.io/sdk/converter" + "go.temporal.io/sdk/temporalnexus" ) @@ -484,35 +484,16 @@ func (c *TemporalWorkflowCountCommand) run(cctx *CommandContext, args []string) return err } - // Just dump response on JSON, otherwise print total and groups + groups := make([]countGroup, len(resp.Groups)) + for i, g := range resp.Groups { + groups[i] = g + } if cctx.JSONOutput { - // Shorthand does not apply to search attributes currently, so we're going - // to remove the "type" from the metadata encoding on group values to make - // it apply - for _, group := range resp.Groups { - for _, payload := range group.GroupValues { - delete(payload.GetMetadata(), "type") - } - } + stripCountGroupMetadataType(groups) return cctx.Printer.PrintStructured(resp, printer.StructuredOptions{}) } - cctx.Printer.Printlnf("Total: %v", resp.Count) - for _, group := range resp.Groups { - // Payload values are search attributes, so we can use the default converter - var valueStr string - for _, payload := range group.GroupValues { - var value any - if err := converter.GetDefaultDataConverter().FromPayload(payload, &value); err != nil { - value = fmt.Sprintf("", err) - } - if valueStr != "" { - valueStr += ", " - } - valueStr += fmt.Sprintf("%v", value) - } - cctx.Printer.Printlnf("Group total: %v, values: %v", group.Count, valueStr) - } + printCountGroupsText(cctx, groups) return nil } diff --git a/internal/temporalcli/commands.yaml b/internal/temporalcli/commands.yaml index d293b75f8..d8cf4ee95 100644 --- a/internal/temporalcli/commands.yaml +++ b/internal/temporalcli/commands.yaml @@ -146,36 +146,30 @@ commands: - common - name: temporal activity - summary: Complete, update, pause, unpause, reset or fail an Activity + summary: Operate on Activity Executions description: | - Update an Activity's options, manage activity lifecycle or update - an Activity's state to completed or failed. - - Updating activity state marks an Activity as successfully finished or as - having encountered an error. - - ``` - temporal activity complete \ - --activity-id=YourActivityId \ - --workflow-id=YourWorkflowId \ - --result='{"YourResultKey": "YourResultValue"}' - ``` + Perform operations on Activity Executions. option-sets: - client docs: description-header: >- - Learn how to use Temporal Activity commands for completing or failing - Activity Executions in your Workflow. Optimize your Temporal Workflow - management effectively. + Learn how to use Temporal Activity commands to perform operations on Activity Executions. keywords: - activity + - activity start + - activity execute + - activity describe + - activity list + - activity count + - activity cancel + - activity terminate + - activity execution - activity complete - activity update-options + - activity fail - activity pause - activity unpause - activity reset - - activity execution - - activity fail - cli reference - cli-feature - command-line-interface-cli @@ -184,8 +178,30 @@ commands: - Activities - Temporal CLI + - name: temporal activity cancel + summary: Request cancellation of a Standalone Activity (Experimental) + description: | + Request cancellation of a Standalone Activity. + + ``` + temporal activity cancel \ + --activity-id YourActivityId + ``` + + Requesting cancellation transitions the Activity's run state + to CancelRequested. If the Activity is heartbeating, a + cancellation error will be raised when the next heartbeat + response is received; if the Activity allows this error to + propagate, the Activity transitions to canceled status. + option-sets: + - activity-reference + options: + - name: reason + type: string + description: Reason for cancellation. + - name: temporal activity complete - summary: Complete an Activity + summary: Mark an activity as completed successfully with a result description: | Complete an Activity, marking it as successfully finished. Specify the Activity ID and include a JSON result for the returned value: @@ -199,20 +215,87 @@ commands: options: - name: activity-id type: string - description: Activity ID to complete. + short: a + description: | + Activity ID. This may be the ID of an Activity + invoked by a Workflow, or of a Standalone Activity. required: true + - name: workflow-id + type: string + short: w + description: | + Workflow ID. Required for workflow Activities. + Omit for Standalone Activities. + - name: run-id + type: string + short: r + description: | + Run ID. For workflow Activities (when --workflow-id is + provided), this is the Workflow Run ID. For Standalone + Activities, this is the Activity Run ID. - name: result type: string description: Result `JSON` to return. required: true + + - name: temporal activity count + summary: Count Standalone Activities matching a query (Experimental) + description: | + Return a count of Standalone Activities. Use `--query` to filter + the activities to be counted. + + ``` + temporal activity count \ + --query 'ActivityType="YourActivity"' + ``` + + Visit https://docs.temporal.io/visibility to read more about + Search Attributes and queries. + options: + - name: query + type: string + short: q + description: | + Query to filter Activity Executions to count. + + - name: temporal activity describe + summary: Show detailed info for a Standalone Activity (Experimental) + description: | + Display information about a Standalone Activity. + + ``` + temporal activity describe \ + --activity-id YourActivityId + ``` option-sets: - - workflow-reference + - activity-reference + options: + - name: raw + type: bool + description: Print properties without changing their format. + + - name: temporal activity execute + summary: Start a new Standalone Activity and wait for its result (Experimental) + description: | + Start a new Standalone Activity and block until it completes. + The result is output to stdout. + + ``` + temporal activity execute \ + --activity-id YourActivityId \ + --type YourActivity \ + --task-queue YourTaskQueue \ + --start-to-close-timeout 30s \ + --input '{"some-key": "some-value"}' + ``` + option-sets: + - activity-start + - payload-input - name: temporal activity fail - summary: Fail an Activity + summary: Mark an Activity as completed unsuccessfully with an error description: | - Fail an Activity, marking it as having encountered an error. Specify the - Activity and Workflow IDs: + Fail an Activity, marking it as having encountered an error: ``` temporal activity fail \ @@ -222,22 +305,68 @@ commands: options: - name: activity-id type: string - description: Activity ID to fail. + short: a + description: | + Activity ID. This may be the ID of an Activity + invoked by a Workflow, or of a Standalone Activity. required: true + - name: workflow-id + type: string + short: w + description: | + Workflow ID. Required for workflow Activities. + Omit for Standalone Activities. + - name: run-id + type: string + short: r + description: | + Run ID. For workflow Activities (when --workflow-id is + provided), this is the Workflow Run ID. For Standalone + Activities, this is the Activity Run ID. - name: detail type: string - description: Reason for failing the Activity (JSON). + description: | + Failure detail (JSON). Attached as the failure details + payload. - name: reason type: string - description: Reason for failing the Activity. - option-sets: - - workflow-reference + description: | + Failure reason. Attached as the failure message. + + - name: temporal activity list + summary: List Standalone Activities matching a query (Experimental) + description: | + List Standalone Activities. Use `--query` to filter results. + + ``` + temporal activity list \ + --query 'ActivityType="YourActivity"' + ``` + + Visit https://docs.temporal.io/visibility to read more about + Search Attributes and queries. + options: + - name: query + short: q + type: string + description: | + Query to filter the Activity Executions to list. + - name: limit + type: int + description: | + Maximum number of Activity Executions to display. + - name: page-size + type: int + description: | + Maximum number of Activity Executions to fetch + at a time from the server. - name: temporal activity update-options - summary: Update Activity options + summary: Change the values of options affecting a running Activity description: | Update the options of a running Activity that were passed into it from a Workflow. Updates are incremental, only changing the specified options. + Not supported for Standalone Activities. For example: @@ -343,7 +472,7 @@ commands: - name: temporal activity pause summary: Pause an Activity description: | - Pause an Activity. + Pause an Activity. Not supported for Standalone Activities. If the Activity is not currently running (e.g. because it previously failed), it will not be run again until it is unpaused. @@ -386,6 +515,7 @@ commands: summary: Unpause an Activity description: | Re-schedule a previously-paused Activity for execution. + Not supported for Standalone Activities. If the Activity is not running and is past its retry timeout, it will be scheduled immediately. Otherwise, it will be scheduled after its retry @@ -451,7 +581,8 @@ commands: - name: temporal activity reset summary: Reset an Activity description: | - Reset an activity. This restarts the activity as if it were first being + Reset an activity. Not supported for Standalone Activities. + This restarts the activity as if it were first being scheduled. That is, it will reset both the number of attempts and the activity timeout, as well as, optionally, the [heartbeat details](#reset-heartbeats). @@ -533,6 +664,58 @@ commands: option-sets: - single-workflow-or-batch + - name: temporal activity result + summary: Wait for and output the result of a Standalone Activity (Experimental) + description: | + Wait for a Standalone Activity to complete and output the + result. + + ``` + temporal activity result \ + --activity-id YourActivityId + ``` + option-sets: + - activity-reference + + - name: temporal activity start + summary: Start a new Standalone Activity (Experimental) + description: | + Start a new Standalone Activity. Outputs the Activity ID and + Run ID. + + ``` + temporal activity start \ + --activity-id YourActivityId \ + --type YourActivity \ + --task-queue YourTaskQueue \ + --start-to-close-timeout 5m \ + --input '{"some-key": "some-value"}' + ``` + option-sets: + - activity-start + - payload-input + + - name: temporal activity terminate + summary: Forcefully end a Standalone Activity (Experimental) + description: | + Terminate a Standalone Activity. + + ``` + temporal activity terminate \ + --activity-id YourActivityId \ + --reason YourReason + ``` + + Activity code cannot see or respond to terminations. + option-sets: + - activity-reference + options: + - name: reason + type: string + description: | + Reason for termination. + Defaults to a message with the current user's name. + - name: temporal batch summary: Manage running batch jobs description: | @@ -1101,17 +1284,17 @@ commands: ``` temporal worker deployment manager-identity [command] [options] ``` - - When present, `ManagerIdentity` is the identity of the user that has the + + When present, `ManagerIdentity` is the identity of the user that has the exclusive right to make changes to this Worker Deployment. Empty by default. When set, users whose identity does not match the `ManagerIdentity` will not be able to change the Worker Deployment. - + This is especially useful in environments where multiple users (such as CLI users and automated controllers) may interact with the same Worker Deployment. `ManagerIdentity` allows different users to communicate with one another about who is expected to make changes to the Worker Deployment. - + The current Manager Identity is returned with `describe`: ``` temporal worker deployment describe \ @@ -1130,12 +1313,12 @@ commands: summary: Set the Manager Identity of a Worker Deployment description: | Set the `ManagerIdentity` of a Worker Deployment given its Deployment Name. - - When present, `ManagerIdentity` is the identity of the user that has the + + When present, `ManagerIdentity` is the identity of the user that has the exclusive right to make changes to this Worker Deployment. Empty by default. When set, users whose identity does not match the `ManagerIdentity` will not be able to change the Worker Deployment. - + This is especially useful in environments where multiple users (such as CLI users and automated controllers) may interact with the same Worker Deployment. `ManagerIdentity` allows different users to communicate with one another about @@ -1144,7 +1327,7 @@ commands: ``` temporal worker deployment manager-identity set [options] ``` - + For example: ``` @@ -1154,17 +1337,17 @@ commands: --identity YourUserIdentity # optional, populated by CLI if not provided ``` - Sets the Manager Identity of the Deployment to the identity of the user making - this request. If you don't specifically pass an identity field, the CLI will + Sets the Manager Identity of the Deployment to the identity of the user making + this request. If you don't specifically pass an identity field, the CLI will generate your identity for you. - + For example: ``` temporal worker deployment manager-identity set \ --deployment-name DeploymentName \ --manager-identity NewManagerIdentity ``` - + Sets the Manager Identity of the Deployment to any string. options: @@ -1186,12 +1369,12 @@ commands: summary: Unset the Manager Identity of a Worker Deployment description: | Unset the `ManagerIdentity` of a Worker Deployment given its Deployment Name. - - When present, `ManagerIdentity` is the identity of the user that has the + + When present, `ManagerIdentity` is the identity of the user that has the exclusive right to make changes to this Worker Deployment. Empty by default. When set, users whose identity does not match the `ManagerIdentity` will not be able to change the Worker Deployment. - + This is especially useful in environments where multiple users (such as CLI users and automated controllers) may interact with the same Worker Deployment. `ManagerIdentity` allows different users to communicate with one another about @@ -1200,7 +1383,7 @@ commands: ``` temporal worker deployment manager-identity unset [options] ``` - + For example: ``` @@ -1223,7 +1406,7 @@ commands: summary: List worker status information in a specific namespace (EXPERIMENTAL) description: | Get a list of workers to the specified namespace. - + ``` temporal worker list --namespace YourNamespace --query 'TaskQueue="YourTaskQueue"' ``` @@ -1240,7 +1423,7 @@ commands: summary: Returns information about a specific worker (EXPERIMENTAL) description: | Look up information of a specific worker. - + ``` temporal worker describe --namespace YourNamespace --worker-instance-key YourKey ``` @@ -2535,8 +2718,8 @@ commands: provided that they were assigned a Build ID. Note that task reachability status is deprecated in favor of Drainage Status - (ie. of a Drained or Draining Worker Deployment Version) and will be removed - in a future release. Also, determining task reachability incurs a non-trivial + (ie. of a Drained or Draining Worker Deployment Version) and will be removed + in a future release. Also, determining task reachability incurs a non-trivial computing cost. Task reachability states are reported per build ID. The state may be one of the @@ -4738,7 +4921,7 @@ option-sets: Temporal workflow headers in 'KEY=VALUE' format. Keys must be identifiers, and values must be JSON values. May be passed multiple times to set multiple Temporal headers. - Note: These are workflow headers, not gRPC headers. + Note: These are workflow headers, not gRPC headers. - name: workflow-update-options options: @@ -4760,3 +4943,139 @@ option-sets: description: When overriding to a `pinned` behavior, specifies the Build ID of the version to target. + + - name: activity-reference + options: + - name: activity-id + type: string + short: a + description: Activity ID. + required: true + - name: run-id + type: string + short: r + description: | + Activity Run ID. + If not set, targets the latest run. + + - name: activity-start + options: + - name: activity-id + type: string + short: a + description: Activity ID. + required: true + - name: type + type: string + description: Activity Type name. + required: true + - name: task-queue + type: string + description: Activity task queue. + required: true + short: t + - name: schedule-to-close-timeout + type: duration + description: | + Maximum time for the Activity Execution, including + all retries. Either this or "start-to-close-timeout" + is required. + - name: schedule-to-start-timeout + type: duration + description: | + Maximum time an Activity task can stay in a task + queue before a Worker picks it up. On expiry it + results in a non-retryable failure and no further + attempts are scheduled. + - name: start-to-close-timeout + type: duration + description: | + Maximum time for a single Activity attempt. + On expiry a new attempt may be scheduled if permitted + by the retry policy and schedule-to-close timeout. + Either this or "schedule-to-close-timeout" + is required. + - name: heartbeat-timeout + type: duration + description: | + Maximum time between successful Worker heartbeats. + On expiry the current activity attempt fails. + - name: retry-initial-interval + type: duration + description: | + Interval of the first retry. + If "retry-backoff-coefficient" is 1.0, it is used + for all retries. + - name: retry-maximum-interval + type: duration + description: | + Maximum interval between retries. + - name: retry-backoff-coefficient + type: float + description: | + Coefficient for calculating the next retry interval. + Must be 1 or larger. + - name: retry-maximum-attempts + type: int + description: | + Maximum number of attempts. + Setting to 1 disables retries. + Setting to 0 means unlimited attempts. + - name: id-reuse-policy + type: string-enum + description: | + Policy for handling activity start when an Activity + with the same ID exists and has completed. + enum-values: + - AllowDuplicate + - AllowDuplicateFailedOnly + - RejectDuplicate + - name: id-conflict-policy + type: string-enum + description: | + Policy for handling activity start when an + Activity with the same ID is currently running. + enum-values: + - Fail + - UseExisting + - name: search-attribute + type: string[] + description: | + Search Attribute in `KEY=VALUE` format. + Keys must be identifiers, and values must be + JSON values. + Can be passed multiple times. + See https://docs.temporal.io/visibility. + - name: headers + type: string[] + description: | + Temporal activity headers in 'KEY=VALUE' format. + Keys must be identifiers, and values must be + JSON values. + May be passed multiple times. + - name: static-summary + type: string + experimental: true + description: | + Static Activity summary for human consumption in UIs. + Uses standard Markdown formatting excluding images, HTML, and script tags. + - name: static-details + type: string + experimental: true + description: | + Static Activity details for human consumption in UIs. + Uses standard Markdown formatting excluding images, HTML, and script tags. + - name: priority-key + type: int + description: | + Priority key (1-5, lower = higher priority). + Default is 3 when not specified. + - name: fairness-key + type: string + description: | + Fairness key (max 64 bytes) for proportional task + dispatch. + - name: fairness-weight + type: float + description: | + Weight [0.001-1000] for this fairness key. diff --git a/internal/temporalcli/commands_test.go b/internal/temporalcli/commands_test.go index 2312e442e..0d5e08805 100644 --- a/internal/temporalcli/commands_test.go +++ b/internal/temporalcli/commands_test.go @@ -233,6 +233,9 @@ func (s *SharedServerSuite) SetupSuite() { "frontend.namespaceRPS.visibility": 10000, // Disable DescribeTaskQueue cache. "frontend.activityAPIsEnabled": true, + "history.enableChasm": true, + "activity.enableStandalone": true, + "activity.longPollTimeout": 2 * time.Second, // this is overridden since we don't want caching to be enabled // while testing DescribeTaskQueue behaviour related to versioning "matching.TaskQueueInfoByBuildIdTTL": 0 * time.Second,