github.com/ydb-platform/ydb-go-sdk/v3@v3.89.2/operation/client.go (about) 1 package operation 2 3 import ( 4 "context" 5 6 "github.com/ydb-platform/ydb-go-genproto/Ydb_Operation_V1" 7 "github.com/ydb-platform/ydb-go-genproto/protos/Ydb" 8 "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Operations" 9 "github.com/ydb-platform/ydb-go-genproto/protos/Ydb_Query" 10 "google.golang.org/grpc" 11 12 "github.com/ydb-platform/ydb-go-sdk/v3/internal/conn" 13 "github.com/ydb-platform/ydb-go-sdk/v3/internal/operation/metadata" 14 "github.com/ydb-platform/ydb-go-sdk/v3/internal/operation/options" 15 "github.com/ydb-platform/ydb-go-sdk/v3/internal/xerrors" 16 "github.com/ydb-platform/ydb-go-sdk/v3/retry" 17 ) 18 19 type ( 20 // Client is an operation service client for manage long operations in YDB 21 // 22 // Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental 23 Client struct { 24 operationServiceClient Ydb_Operation_V1.OperationServiceClient 25 } 26 // Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental 27 listOperationsWithNextToken[PT metadata.Constraint[T], T metadata.TypesConstraint] struct { 28 listOperations[PT, T] 29 NextToken string 30 } 31 // Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental 32 listOperations[PT metadata.Constraint[T], T metadata.TypesConstraint] struct { 33 Operations []*typedOperation[PT, T] 34 } 35 operation struct { 36 ID string 37 Ready bool 38 Status string 39 ConsumedUnits float64 40 } 41 // Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental 42 typedOperation[PT metadata.Constraint[T], T metadata.TypesConstraint] struct { 43 operation 44 Metadata *T 45 } 46 ) 47 48 // Get returns operation status by ID 49 // 50 // Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental 51 func (c *Client) Get(ctx context.Context, opID string) (*operation, error) { 52 op, err := get(ctx, c.operationServiceClient, opID) 53 if err != nil { 54 return nil, xerrors.WithStackTrace(err) 55 } 56 57 return op, nil 58 } 59 60 func get( 61 ctx context.Context, client Ydb_Operation_V1.OperationServiceClient, opID string, 62 ) (*operation, error) { 63 status, err := retry.RetryWithResult(ctx, func(ctx context.Context) (*operation, error) { 64 response, err := client.GetOperation( 65 conn.WithoutWrapping(ctx), 66 &Ydb_Operations.GetOperationRequest{ 67 Id: opID, 68 }, 69 ) 70 if err != nil { 71 return nil, xerrors.WithStackTrace(err) 72 } 73 74 var md Ydb_Query.ExecuteScriptMetadata 75 err = response.GetOperation().GetMetadata().UnmarshalTo(&md) 76 if err != nil { 77 return nil, xerrors.WithStackTrace(err) 78 } 79 80 return &operation{ 81 Ready: response.GetOperation().GetReady(), 82 Status: response.GetOperation().GetStatus().String(), 83 }, nil 84 }, retry.WithIdempotent(true)) 85 if err != nil { 86 return nil, xerrors.WithStackTrace(err) 87 } 88 89 return status, nil 90 } 91 92 func list[PT metadata.Constraint[T], T metadata.TypesConstraint]( 93 ctx context.Context, client Ydb_Operation_V1.OperationServiceClient, request *Ydb_Operations.ListOperationsRequest, 94 ) (*listOperationsWithNextToken[PT, T], error) { 95 operations, err := retry.RetryWithResult(ctx, func(ctx context.Context) ( 96 operations *listOperationsWithNextToken[PT, T], _ error, 97 ) { 98 response, err := client.ListOperations(conn.WithoutWrapping(ctx), request) 99 if err != nil { 100 return nil, xerrors.WithStackTrace(err) 101 } 102 103 if response.GetStatus() != Ydb.StatusIds_SUCCESS { 104 return nil, xerrors.WithStackTrace(xerrors.Operation( 105 xerrors.WithStatusCode(response.GetStatus()), 106 xerrors.WithIssues(response.GetIssues()), 107 )) 108 } 109 110 operations = &listOperationsWithNextToken[PT, T]{ 111 listOperations: listOperations[PT, T]{ 112 Operations: make([]*typedOperation[PT, T], 0, len(response.GetOperations())), 113 }, 114 NextToken: response.GetNextPageToken(), 115 } 116 117 for _, op := range response.GetOperations() { 118 operations.Operations = append(operations.Operations, &typedOperation[PT, T]{ 119 operation: operation{ 120 ID: op.GetId(), 121 Ready: op.GetReady(), 122 Status: op.GetStatus().String(), 123 ConsumedUnits: op.GetCostInfo().GetConsumedUnits(), 124 }, 125 Metadata: metadata.FromProto[PT, T](op.GetMetadata()), 126 }) 127 } 128 129 return operations, nil 130 }, retry.WithIdempotent(true)) 131 if err != nil { 132 return nil, xerrors.WithStackTrace(err) 133 } 134 135 return operations, nil 136 } 137 138 func cancel( 139 ctx context.Context, client Ydb_Operation_V1.OperationServiceClient, opID string, 140 ) error { 141 err := retry.Retry(ctx, func(ctx context.Context) error { 142 response, err := client.CancelOperation(conn.WithoutWrapping(ctx), &Ydb_Operations.CancelOperationRequest{ 143 Id: opID, 144 }) 145 if err != nil { 146 return xerrors.WithStackTrace(err) 147 } 148 149 if response.GetStatus() != Ydb.StatusIds_SUCCESS { 150 return xerrors.WithStackTrace(xerrors.Operation( 151 xerrors.WithStatusCode(response.GetStatus()), 152 xerrors.WithIssues(response.GetIssues()), 153 )) 154 } 155 156 return nil 157 }, retry.WithIdempotent(true)) 158 if err != nil { 159 return xerrors.WithStackTrace(err) 160 } 161 162 return nil 163 } 164 165 // Cancel starts cancellation of a long-running operation. 166 // 167 // Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental 168 func (c *Client) Cancel(ctx context.Context, opID string) error { 169 err := cancel(ctx, c.operationServiceClient, opID) 170 if err != nil { 171 return xerrors.WithStackTrace(err) 172 } 173 174 return nil 175 } 176 177 func forget( 178 ctx context.Context, client Ydb_Operation_V1.OperationServiceClient, opID string, 179 ) error { 180 err := retry.Retry(ctx, func(ctx context.Context) error { 181 response, err := client.ForgetOperation(conn.WithoutWrapping(ctx), &Ydb_Operations.ForgetOperationRequest{ 182 Id: opID, 183 }) 184 if err != nil { 185 return xerrors.WithStackTrace(err) 186 } 187 188 if response.GetStatus() != Ydb.StatusIds_SUCCESS { 189 return xerrors.WithStackTrace(xerrors.Operation( 190 xerrors.WithStatusCode(response.GetStatus()), 191 xerrors.WithIssues(response.GetIssues()), 192 )) 193 } 194 195 return nil 196 }, retry.WithIdempotent(true)) 197 if err != nil { 198 return xerrors.WithStackTrace(err) 199 } 200 201 return nil 202 } 203 204 // Forget forgets long-running operation. It does not cancel the operation and 205 // returns an error if operation was not completed. 206 // 207 // Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental 208 func (c *Client) Forget(ctx context.Context, opID string) error { 209 err := forget(ctx, c.operationServiceClient, opID) 210 if err != nil { 211 return xerrors.WithStackTrace(err) 212 } 213 214 return nil 215 } 216 217 func (c *Client) Close(ctx context.Context) error { 218 return nil 219 } 220 221 // ListBuildIndex returns list of build index operations 222 // 223 // Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental 224 func (c *Client) ListBuildIndex(ctx context.Context) ( 225 *listOperations[*metadata.BuildIndex, metadata.BuildIndex], error, 226 ) { 227 request := &options.ListOperationsRequest{ 228 ListOperationsRequest: Ydb_Operations.ListOperationsRequest{ 229 Kind: kindBuildIndex, 230 }, 231 } 232 233 operations, err := list[*metadata.BuildIndex, metadata.BuildIndex]( 234 ctx, c.operationServiceClient, &request.ListOperationsRequest, 235 ) 236 if err != nil { 237 return nil, xerrors.WithStackTrace(err) 238 } 239 240 return &operations.listOperations, nil 241 } 242 243 // ListImportFromS3 returns list of import from s3 operations 244 // 245 // Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental 246 func (c *Client) ListImportFromS3(ctx context.Context) ( 247 *listOperations[*metadata.ImportFromS3, metadata.ImportFromS3], error, 248 ) { 249 request := &options.ListOperationsRequest{ 250 ListOperationsRequest: Ydb_Operations.ListOperationsRequest{ 251 Kind: kindImportFromS3, 252 }, 253 } 254 255 operations, err := list[*metadata.ImportFromS3, metadata.ImportFromS3]( 256 ctx, c.operationServiceClient, &request.ListOperationsRequest, 257 ) 258 if err != nil { 259 return nil, xerrors.WithStackTrace(err) 260 } 261 262 return &operations.listOperations, nil 263 } 264 265 // ListExportToS3 returns list of export to s3 operations 266 // 267 // Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental 268 func (c *Client) ListExportToS3(ctx context.Context) ( 269 *listOperations[*metadata.ExportToS3, metadata.ExportToS3], error, 270 ) { 271 request := &options.ListOperationsRequest{ 272 ListOperationsRequest: Ydb_Operations.ListOperationsRequest{ 273 Kind: kindExportToS3, 274 }, 275 } 276 277 operations, err := list[*metadata.ExportToS3, metadata.ExportToS3]( 278 ctx, c.operationServiceClient, &request.ListOperationsRequest, 279 ) 280 if err != nil { 281 return nil, xerrors.WithStackTrace(err) 282 } 283 284 return &operations.listOperations, nil 285 } 286 287 // ListExportToYT returns list of export to YT operations 288 // 289 // Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental 290 func (c *Client) ListExportToYT(ctx context.Context) ( 291 *listOperations[*metadata.ExportToYT, metadata.ExportToYT], error, 292 ) { 293 request := &options.ListOperationsRequest{ 294 ListOperationsRequest: Ydb_Operations.ListOperationsRequest{ 295 Kind: kindExportToYT, 296 }, 297 } 298 299 operations, err := list[*metadata.ExportToYT, metadata.ExportToYT]( 300 ctx, c.operationServiceClient, &request.ListOperationsRequest, 301 ) 302 if err != nil { 303 return nil, xerrors.WithStackTrace(err) 304 } 305 306 return &operations.listOperations, nil 307 } 308 309 // ListExecuteQuery returns list of query executions 310 // 311 // Experimental: https://github.com/ydb-platform/ydb-go-sdk/blob/master/VERSIONING.md#experimental 312 func (c *Client) ListExecuteQuery(ctx context.Context, opts ...options.List) ( 313 *listOperationsWithNextToken[*metadata.ExecuteQuery, metadata.ExecuteQuery], error, 314 ) { 315 request := &options.ListOperationsRequest{ 316 ListOperationsRequest: Ydb_Operations.ListOperationsRequest{ 317 Kind: kindExecuteQuery, 318 }, 319 } 320 321 for _, opt := range opts { 322 if opt != nil { 323 opt(request) 324 } 325 } 326 327 operations, err := list[*metadata.ExecuteQuery, metadata.ExecuteQuery]( 328 ctx, c.operationServiceClient, &request.ListOperationsRequest, 329 ) 330 if err != nil { 331 return nil, xerrors.WithStackTrace(err) 332 } 333 334 return operations, nil 335 } 336 337 func New(ctx context.Context, balancer grpc.ClientConnInterface) *Client { 338 return &Client{ 339 operationServiceClient: Ydb_Operation_V1.NewOperationServiceClient( 340 conn.WithContextModifier(balancer, conn.WithoutWrapping), 341 ), 342 } 343 }