@@ -2,6 +2,7 @@ package github
2
2
3
3
import (
4
4
"bytes"
5
+ "context"
5
6
"io"
6
7
"log"
7
8
"net/http"
@@ -65,7 +66,7 @@ func (rlt *RateLimitTransport) RoundTrip(req *http.Request) (*http.Response, err
65
66
// for read and write requests. See isWriteMethod for the distinction between them.
66
67
if rlt .nextRequestDelay > 0 {
67
68
log .Printf ("[DEBUG] Sleeping %s between operations" , rlt .nextRequestDelay )
68
- time . Sleep ( rlt .nextRequestDelay )
69
+ sleep ( req . Context (), rlt .nextRequestDelay )
69
70
}
70
71
71
72
rlt .nextRequestDelay = rlt .calculateNextDelay (req .Method )
@@ -81,6 +82,7 @@ func (rlt *RateLimitTransport) RoundTrip(req *http.Request) (*http.Response, err
81
82
// See https://github.com/google/go-github/pull/986
82
83
r1 , r2 , err := drainBody (resp .Body )
83
84
if err != nil {
85
+ rlt .smartLock (false )
84
86
return nil , err
85
87
}
86
88
resp .Body = r1
@@ -93,7 +95,7 @@ func (rlt *RateLimitTransport) RoundTrip(req *http.Request) (*http.Response, err
93
95
retryAfter := arlErr .GetRetryAfter ()
94
96
log .Printf ("[DEBUG] Abuse detection mechanism triggered, sleeping for %s before retrying" ,
95
97
retryAfter )
96
- time . Sleep ( retryAfter )
98
+ sleep ( req . Context (), retryAfter )
97
99
rlt .smartLock (false )
98
100
return rlt .RoundTrip (req )
99
101
}
@@ -103,7 +105,7 @@ func (rlt *RateLimitTransport) RoundTrip(req *http.Request) (*http.Response, err
103
105
retryAfter := time .Until (rlErr .Rate .Reset .Time )
104
106
log .Printf ("[DEBUG] Rate limit %d reached, sleeping for %s (until %s) before retrying" ,
105
107
rlErr .Rate .Limit , retryAfter , time .Now ().Add (retryAfter ))
106
- time . Sleep ( retryAfter )
108
+ sleep ( req . Context (), retryAfter )
107
109
rlt .smartLock (false )
108
110
return rlt .RoundTrip (req )
109
111
}
@@ -113,6 +115,16 @@ func (rlt *RateLimitTransport) RoundTrip(req *http.Request) (*http.Response, err
113
115
return resp , nil
114
116
}
115
117
118
+ func sleep (ctx context.Context , dur time.Duration ) {
119
+ t := time .NewTimer (dur )
120
+ defer t .Stop ()
121
+
122
+ select {
123
+ case <- t .C :
124
+ case <- ctx .Done ():
125
+ }
126
+ }
127
+
116
128
// smartLock wraps the mutex locking system and performs its operation via a boolean input for locking and unlocking.
117
129
// It also skips the locking when parallelRequests is set to true since, in this case, the lock is not needed.
118
130
func (rlt * RateLimitTransport ) smartLock (lock bool ) {
0 commit comments