Configure statement timeout

This page describes how to set a timeout for a single statement execution using the Spanner client libraries. This can be used to override the default timeout configuration of the client library. The statement fails with a DEADLINE_EXCEEDED error if the statement cannot finish within the given timeout value.

These samples show how to set a timeout for a single statement execution in the Cloud Spanner client library.

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 
 ; 
  
 }) 
  
 ); 
 } 
 

Node.js

  /** 
 * TODO(developer): Uncomment the following lines before running the sample. 
 */ 
 // const projectId = 'my-project-id'; 
 // const instanceId = 'my-instance'; 
 // const databaseId = 'my-database'; 
 // Imports the Google Cloud client library 
 const 
  
 { 
 Spanner 
 } 
  
 = 
  
 require 
 ( 
 ' @google-cloud/spanner 
' 
 ); 
 // Creates a client 
 const 
  
 spanner 
  
 = 
  
 new 
  
  Spanner 
 
 ({ 
  
 projectId 
 : 
  
 projectId 
 , 
 }); 
 async 
  
 function 
  
 executeSqlWithTimeout 
 () 
  
 { 
  
 // Gets a reference to a Cloud Spanner instance and database. 
  
 const 
  
 instance 
  
 = 
  
 spanner 
 . 
 instance 
 ( 
 instanceId 
 ); 
  
 const 
  
 database 
  
 = 
  
 instance 
 . 
 database 
 ( 
 databaseId 
 ); 
  
 try 
  
 { 
  
 await 
  
 database 
 . 
  runTransactionAsync 
 
 ( 
 async 
  
 tx 
  
 = 
>  
 { 
  
 // NOTE: You can use gaxOptions 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. 
  
 const 
  
 query 
  
 = 
  
 { 
  
 sql 
 : 
  
 "INSERT INTO Singers (SingerId, FirstName, LastName) VALUES (110, 'George', 'Washington')" 
 , 
  
 gaxOptions 
 : 
  
 { 
  
 timeout 
 : 
  
 60000 
 , 
  
 // 60 seconds timeout 
  
 }, 
  
 }; 
  
 const 
  
 results 
  
 = 
  
 await 
  
 tx 
 . 
 run 
 ( 
 query 
 ); 
  
 console 
 . 
 log 
 ( 
 ` 
 ${ 
 results 
 [ 
 1 
 ]. 
 rowCountExact 
 } 
 record inserted.` 
 ); 
  
 await 
  
 tx 
 . 
 commit 
 (); 
  
 }); 
  
 } 
  
 catch 
  
 ( 
 err 
 ) 
  
 { 
  
 console 
 . 
 error 
 ( 
 'ERROR:' 
 , 
  
 err 
 ); 
  
 } 
  
 finally 
  
 { 
  
 await 
  
 database 
 . 
 close 
 (); 
  
 } 
 } 
 executeSqlWithTimeout 
 (); 
 

Python

  # instance_id = "your-spanner-instance" 
 # database_id = "your-spanner-db-id" 
 spanner_client 
 = 
 spanner 
 . 
 Client 
 () 
 instance 
 = 
 spanner_client 
 . 
 instance 
 ( 
 instance_id 
 ) 
 database 
 = 
 instance 
 . 
 database 
 ( 
 database_id 
 ) 
 def 
  
 write 
 ( 
 transaction 
 ): 
 # Insert a record and configure the statement timeout to 60 seconds 
 # 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. 
 row_ct 
 = 
 transaction 
 . 
 execute_update 
 ( 
 "INSERT INTO Singers (SingerId, FirstName, LastName) " 
 " VALUES (110, 'George', 'Washington')" 
 , 
 timeout 
 = 
 60 
 , 
 ) 
 print 
 ( 
 " 
 {} 
 record(s) inserted." 
 . 
 format 
 ( 
 row_ct 
 )) 
 database 
 . 
 run_in_transaction 
 ( 
 write 
 ) 
 
Design a Mobile Site
View Site in Mobile | Classic
Share by: