Index: common/prpc/timeout.go |
diff --git a/server/prpc/timeout.go b/common/prpc/timeout.go |
similarity index 51% |
rename from server/prpc/timeout.go |
rename to common/prpc/timeout.go |
index 9811395ff985f533ca6a1d928e5715b37bb040f6..25d3aec9c05c004518f6af56b07cea340cadda87 100644 |
--- a/server/prpc/timeout.go |
+++ b/common/prpc/timeout.go |
@@ -10,10 +10,6 @@ import ( |
"time" |
) |
-// headerTimeout is HTTP header used to set pRPC request timeout. |
-// The single value should match regexp `\d+[HMSmun]`. |
-const headerTimeout = "X-Prpc-Timeout" |
- |
// The rest of this file is adapted from |
// https://github.com/grpc/grpc-go/blob/6a026b9f108b49838491178e5d9bf7a4dcf32cf2/transport/http_util.go#L295 |
@@ -47,7 +43,8 @@ func timeoutUnitToDuration(u timeoutUnit) (d time.Duration, ok bool) { |
return |
} |
-func decodeTimeout(s string) (time.Duration, error) { |
+// DecodeTimeout decodes a gRPC/pRPC timeout header string into a time.Duration. |
+func DecodeTimeout(s string) (time.Duration, error) { |
size := len(s) |
if size < 2 { |
return 0, fmt.Errorf("too short: %q", s) |
@@ -63,3 +60,39 @@ func decodeTimeout(s string) (time.Duration, error) { |
} |
return d * time.Duration(t), nil |
} |
+ |
+const maxTimeoutValue int64 = 100000000 - 1 |
+ |
+// div does integer division and round-up the result. Note that this is |
+// equivalent to (d+r-1)/r but has less chance to overflow. |
+func div(d, r time.Duration) int64 { |
+ if m := d % r; m > 0 { |
+ return int64(d/r + 1) |
+ } |
+ return int64(d / r) |
+} |
+ |
+// EncodeTimeout encodes a gRPC/pRPC timeout into a timeout header |
+// time.Duration. |
+// |
+// This rounds the time.Duration to the smallest time unit that can represent |
+// it. |
+func EncodeTimeout(t time.Duration) string { |
+ if d := div(t, time.Nanosecond); d <= maxTimeoutValue { |
+ return strconv.FormatInt(d, 10) + "n" |
+ } |
+ if d := div(t, time.Microsecond); d <= maxTimeoutValue { |
+ return strconv.FormatInt(d, 10) + "u" |
+ } |
+ if d := div(t, time.Millisecond); d <= maxTimeoutValue { |
+ return strconv.FormatInt(d, 10) + "m" |
+ } |
+ if d := div(t, time.Second); d <= maxTimeoutValue { |
+ return strconv.FormatInt(d, 10) + "S" |
+ } |
+ if d := div(t, time.Minute); d <= maxTimeoutValue { |
+ return strconv.FormatInt(d, 10) + "M" |
+ } |
+ // Note that maxTimeoutValue * time.Hour > MaxInt64. |
+ return strconv.FormatInt(div(t, time.Hour), 10) + "H" |
+} |