@@ -56,16 +56,7 @@ const (
5656 cancelOperation
5757)
5858
59- var idempotentClientMethods map [clientMethod ]any = map [clientMethod ]any {
60- closeSession : struct {}{},
61- getResultSetMetadata : struct {}{},
62- getOperationStatus : struct {}{},
63- closeOperation : struct {}{},
64- cancelOperation : struct {}{},
65- // fetchResults is treated as idempotent because the drivers fetching logic is robust enoug
66- // to fetch results in correct order
67- fetchResults : struct {}{},
68- }
59+ var nonRetryableClientMethods map [clientMethod ]any = map [clientMethod ]any {executeStatement : struct {}{}}
6960
7061// OpenSession is a wrapper around the thrift operation OpenSession
7162// If RecordResults is true, the results will be marshalled to JSON format and written to OpenSession<index>.json
@@ -449,27 +440,24 @@ func errorHandler(resp *http.Response, err error, numTries int) (*http.Response,
449440 var werr error
450441 msg := fmt .Sprintf ("request error after %d attempt(s)" , numTries )
451442 if err == nil {
452- err = errors .New (msg )
443+ werr = errors .New (msg )
453444 } else {
454- err = errors .Wrap (err , msg )
445+ werr = errors .Wrap (err , msg )
455446 }
456447
457448 if resp != nil {
458- var orgid , reason , terrmsg , errmsg string
459- // TODO @mattdeekay: convert these to specific error types
460449 if resp .Header != nil {
461- orgid = resp .Header .Get ("X-Databricks-Org-Id" )
462- reason = resp .Header .Get ("X-Databricks-Reason-Phrase" ) // TODO note: shown on notebook
463- terrmsg = resp .Header .Get ("X-Thriftserver-Error-Message" )
464- errmsg = resp .Header .Get ("x-databricks-error-or-redirect-message" )
465- // TODO note: need to see if there's other headers
450+ reason := resp .Header .Get ("X-Databricks-Reason-Phrase" )
451+ terrmsg := resp .Header .Get ("X-Thriftserver-Error-Message" )
452+
453+ if reason != "" {
454+ werr = dbsqlerrint .WrapErr (werr , reason )
455+ } else if terrmsg != "" {
456+ werr = dbsqlerrint .WrapErr (werr , terrmsg )
457+ }
466458 }
467- msg := fmt .Sprintf ("orgId: %s, reason: %s, thriftErr: %s, err: %s" , orgid , reason , terrmsg , errmsg )
468459
469- werr = dbsqlerrint .WrapErr (err , msg )
470460 logger .Err (werr ).Msg (resp .Status )
471- } else {
472- werr = err
473461 }
474462
475463 return resp , werr
@@ -526,7 +514,7 @@ func RetryPolicy(ctx context.Context, resp *http.Response, err error) (bool, err
526514 // 429 Too Many Requests or 503 service unavailable is recoverable. Sometimes the server puts
527515 // a Retry-After response header to indicate when the server is
528516 // available to start processing request from client.
529- if resp . StatusCode == http . StatusTooManyRequests || resp . StatusCode == http . StatusServiceUnavailable {
517+ if isRetryableServerResponse ( resp ) {
530518 var retryAfter string
531519 if resp .Header != nil {
532520 retryAfter = resp .Header .Get ("Retry-After" )
@@ -538,7 +526,7 @@ func RetryPolicy(ctx context.Context, resp *http.Response, err error) (bool, err
538526 if resp .StatusCode == 0 || (resp .StatusCode >= 500 && resp .StatusCode != http .StatusNotImplemented ) {
539527 callerAny := ctx .Value (ClientMethod )
540528 if caller , ok := callerAny .(clientMethod ); ok {
541- if _ , ok := idempotentClientMethods [caller ]; ok {
529+ if _ , noRetry := nonRetryableClientMethods [caller ]; ! noRetry {
542530 return true , checkErr
543531 }
544532 }
@@ -550,14 +538,16 @@ func RetryPolicy(ctx context.Context, resp *http.Response, err error) (bool, err
550538}
551539
552540func backoff (min , max time.Duration , attemptNum int , resp * http.Response ) time.Duration {
553- if resp != nil && isRetryableServerResponse (resp ) {
541+ // honour the Retry-After header
542+ if resp != nil && resp .Header != nil {
554543 if s , ok := resp .Header ["Retry-After" ]; ok {
555544 if sleep , err := strconv .ParseInt (s [0 ], 10 , 64 ); err == nil {
556545 return time .Second * time .Duration (sleep )
557546 }
558547 }
559548 }
560549
550+ // exponential backoff
561551 mult := math .Pow (2 , float64 (attemptNum )) * float64 (min )
562552 sleep := time .Duration (mult )
563553 if float64 (sleep ) != mult || sleep > max {
0 commit comments