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  }