Configurer le délai avant expiration de l'instruction

Cette page explique comment définir un délai d'expiration pour l'exécution d'une seule instruction à l'aide de les bibliothèques clientes Spanner. Vous pouvez l'utiliser pour remplacer la configuration de délai d'expiration par défaut de la bibliothèque cliente. L'instruction échoue avec une erreur DEADLINE_EXCEEDED si elle ne peut pas se terminer dans la valeur de délai avant expiration donnée.

Ces exemples montrent comment définir un délai avant expiration pour une seule exécution d'instruction dans la bibliothèque cliente Cloud Spanner.

Go


import (
	"context"
	"fmt"
	"io"
	"time"

	"cloud.google.com/go/spanner"
	"google.golang.org/grpc/codes"
)

func setStatementTimeout(w io.Writer, db string) error {
	client, err := spanner.NewClient(context.Background(), db)
	if err != nil {
		return err
	}
	defer client.Close()

	_, err = client.ReadWriteTransaction(context.Background(),
		func(ctx context.Context, txn *spanner.ReadWriteTransaction) error {
			// Create a context with a 60-second timeout and apply this timeout to the insert statement.
			ctxWithTimeout, cancel := context.WithTimeout(context.Background(), 60*time.Second)
			defer cancel()
			stmt := spanner.Statement{
				SQL: `INSERT Singers (SingerId, FirstName, LastName)
					VALUES (39, 'George', 'Washington')`,
			}
			rowCount, err := txn.Update(ctxWithTimeout, stmt)
			// Get the error code from the error. This function returns codes.OK if err == nil.
			code := spanner.ErrCode(err)
			if code == codes.DeadlineExceeded {
				fmt.Fprintf(w, "Insert statement timed out.\n")
			} else if code == codes.OK {
				fmt.Fprintf(w, "%d record(s) inserted.\n", rowCount)
			} else {
				fmt.Fprintf(w, "Insert statement failed with error %v\n", err)
			}
			return err
		})
	if err != nil {
		return err
	}
	return nil
}

Java


static void executeSqlWithTimeout() {
  // TODO(developer): Replace these variables before running the sample.
  String projectId = "my-project";
  String instanceId = "my-instance";
  String databaseId = "my-database";

  try (Spanner spanner =
      SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
    DatabaseClient client =
        spanner.getDatabaseClient(DatabaseId.of(projectId, instanceId, databaseId));
    executeSqlWithTimeout(client);
  }
}

static void executeSqlWithTimeout(DatabaseClient client) {
  CallContextConfigurator configurator = new CallContextConfigurator() {
    public <ReqT, RespT> ApiCallContext configure(ApiCallContext context, ReqT request,
        MethodDescriptor<ReqT, RespT> method) {
      // DML uses the ExecuteSql RPC.
      if (method == SpannerGrpc.getExecuteSqlMethod()) {
        // NOTE: You can use a GrpcCallContext to set a custom timeout for a single RPC
        // invocation. This timeout can however ONLY BE SHORTER than the default timeout
        // for the RPC. If you set a timeout that is longer than the default timeout, then
        // the default timeout will be used.
        return GrpcCallContext.createDefault()
            .withCallOptions(CallOptions.DEFAULT.withDeadlineAfter(60L, TimeUnit.SECONDS));
      }
      // Return null to indicate that the default should be used for other methods.
      return null;
    }
  };
  // Create a context that uses the custom call configuration.
  Context context =
      Context.current().withValue(SpannerOptions.CALL_CONTEXT_CONFIGURATOR_KEY, configurator);
  // Run the transaction in the custom context.
  context.run(() ->
      client.readWriteTransaction().<long[]>run(transaction -> {
        String sql = "INSERT INTO Singers (SingerId, FirstName, LastName)\n"
            + "VALUES (20, 'George', 'Washington')";
        long rowCount = transaction.executeUpdate(Statement.of(sql));
        System.out.printf("%d record inserted.%n", rowCount);
        return null;
      })
  );
}