Skip to content

Commit

Permalink
Support grpc-previous-rpc-attempts
Browse files Browse the repository at this point in the history
This is a tiny step towards #104.
  • Loading branch information
edsko committed Mar 29, 2024
1 parent be3e978 commit 5f3744c
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 20 deletions.
2 changes: 2 additions & 0 deletions src/Network/GRPC/Client/Connection.hs
Original file line number Diff line number Diff line change
Expand Up @@ -356,6 +356,8 @@ startRPC Connection{connMetaVar, connParams, connStateVar} _ callParams = do
True
, requestTraceContext =
Nothing
, requestPreviousRpcAttempts =
Nothing
}

callSession :: ClientSession rpc
Expand Down
58 changes: 42 additions & 16 deletions src/Network/GRPC/Spec/Request.hs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@ import Network.GRPC.Util.HKD (HKD, Undecorated, DecoratedWith)
import Network.GRPC.Util.HKD qualified as HKD

import Paths_grapesy qualified as Grapesy
import Text.Read (readMaybe)

{-------------------------------------------------------------------------------
Inputs (message sent to the peer)
Expand Down Expand Up @@ -100,6 +101,12 @@ data RequestHeaders_ f = RequestHeaders {

-- | Trace context (for OpenTelemetry)
, requestTraceContext :: HKD f (Maybe TraceContext)

-- | Previous RPC attempts
--
-- This is part of automatic retries.
-- See <https://github.com/grpc/proposal/blob/master/A6-client-retries.md>.
, requestPreviousRpcAttempts :: HKD f (Maybe Int)
}

type RequestHeaders = RequestHeaders_ Undecorated
Expand All @@ -110,14 +117,15 @@ deriving stock instance Eq RequestHeaders
instance HKD.Traversable RequestHeaders_ where
sequence x =
RequestHeaders
<$> requestTimeout x
<*> requestMetadata x
<*> requestCompression x
<*> requestAcceptCompression x
<*> requestContentType x
<*> requestMessageType x
<*> requestIncludeTE x
<*> requestTraceContext x
<$> requestTimeout x
<*> requestMetadata x
<*> requestCompression x
<*> requestAcceptCompression x
<*> requestContentType x
<*> requestMessageType x
<*> requestIncludeTE x
<*> requestTraceContext x
<*> requestPreviousRpcAttempts x

-- | Mark a input sent as final
data IsFinal = Final | NotFinal
Expand Down Expand Up @@ -179,6 +187,7 @@ callDefinition proxy = \hdrs -> catMaybes [
, buildMessageAcceptEncoding <$> requestAcceptCompression hdrs
, Just $ buildUserAgent
, buildGrpcTraceBin <$> requestTraceContext hdrs
, buildPreviousRpcAttempts <$> requestPreviousRpcAttempts hdrs
]
where
hdrTimeout :: Timeout -> HTTP.Header
Expand Down Expand Up @@ -229,6 +238,12 @@ callDefinition proxy = \hdrs -> catMaybes [
, buildBinaryValue $ buildTraceContext ctxt
)

buildPreviousRpcAttempts :: Int -> HTTP.Header
buildPreviousRpcAttempts n = (
"grpc-previous-rpc-attempts"
, BS.Strict.C8.pack $ show n
)

{-------------------------------------------------------------------------------
Parsing
-------------------------------------------------------------------------------}
Expand Down Expand Up @@ -299,6 +314,16 @@ parseRequestHeaders proxy =
return True
}

| name == "grpc-previous-rpc-attempts"
= modify $ \x -> x {
requestPreviousRpcAttempts = do
httpError HTTP.badRequest400 $
maybe
(Left $ "grpc-previous-rpc-attempts: invalid " ++ show value)
(Right . Just)
(readMaybe $ BS.Strict.C8.unpack value)
}

| otherwise
= modify $ \x -> x {
requestMetadata = do
Expand All @@ -308,14 +333,15 @@ parseRequestHeaders proxy =

uninitRequestHeaders :: RequestHeaders_ (DecoratedWith m)
uninitRequestHeaders = RequestHeaders {
requestTimeout = return Nothing
, requestMetadata = return mempty
, requestCompression = return Nothing
, requestAcceptCompression = return Nothing
, requestContentType = return Nothing
, requestMessageType = return False
, requestIncludeTE = return False
, requestTraceContext = return Nothing
requestTimeout = return Nothing
, requestMetadata = return mempty
, requestCompression = return Nothing
, requestAcceptCompression = return Nothing
, requestContentType = return Nothing
, requestMessageType = return False
, requestIncludeTE = return False
, requestTraceContext = return Nothing
, requestPreviousRpcAttempts = return Nothing
}

httpError ::
Expand Down
3 changes: 3 additions & 0 deletions src/Network/GRPC/Spec/Response.hs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,9 @@ data ProperTrailers_ f = ProperTrailers {
, properTrailersMetadata :: HKD f CustomMetadataMap

-- | Server pushback
--
-- This is part of automatic retries.
-- See <https://github.com/grpc/proposal/blob/master/A6-client-retries.md>.
, properTrailersPushback :: HKD f (Maybe Pushback)

-- | ORCA load report
Expand Down
12 changes: 8 additions & 4 deletions test-grapesy/Test/Prop/Serialization.hs
Original file line number Diff line number Diff line change
Expand Up @@ -300,6 +300,7 @@ instance Arbitrary (Awkward RequestHeaders) where
requestMessageType <- arbitrary
requestIncludeTE <- arbitrary
requestTraceContext <- awkward
requestPreviousRpcAttempts <- awkward
return $ RequestHeaders{
requestTimeout
, requestMetadata
Expand All @@ -309,6 +310,7 @@ instance Arbitrary (Awkward RequestHeaders) where
, requestMessageType
, requestIncludeTE
, requestTraceContext
, requestPreviousRpcAttempts
}
shrink h@(Awkward h') = concat [
shrinkAwkward (\x -> h'{requestTimeout = x}) requestTimeout h
Expand All @@ -319,6 +321,7 @@ instance Arbitrary (Awkward RequestHeaders) where
, shrinkRegular (\x -> h'{requestMessageType = x}) requestMessageType h
, shrinkRegular (\x -> h'{requestIncludeTE = x}) requestIncludeTE h
, shrinkAwkward (\x -> h'{requestTraceContext = x}) requestTraceContext h
, shrinkAwkward (\x -> h'{requestPreviousRpcAttempts = x}) requestPreviousRpcAttempts h
]

instance Arbitrary (Awkward ResponseHeaders) where
Expand Down Expand Up @@ -357,10 +360,11 @@ instance Arbitrary (Awkward ProperTrailers) where
}

shrink h@(Awkward h') = concat [
shrinkAwkward (\x -> h'{properTrailersGrpcStatus = x}) properTrailersGrpcStatus h
, shrinkAwkward (\x -> h'{properTrailersGrpcMessage = x}) properTrailersGrpcMessage h
, shrinkAwkward (\x -> h'{properTrailersMetadata = x}) properTrailersMetadata h
, shrinkAwkward (\x -> h'{properTrailersPushback = x}) properTrailersPushback h
shrinkAwkward (\x -> h'{properTrailersGrpcStatus = x}) properTrailersGrpcStatus h
, shrinkAwkward (\x -> h'{properTrailersGrpcMessage = x}) properTrailersGrpcMessage h
, shrinkAwkward (\x -> h'{properTrailersMetadata = x}) properTrailersMetadata h
, shrinkAwkward (\x -> h'{properTrailersPushback = x}) properTrailersPushback h
, shrinkAwkward (\x -> h'{properTrailersOrcaLoadReport = x}) properTrailersOrcaLoadReport h
]

instance Arbitrary (Awkward TrailersOnly) where
Expand Down
4 changes: 4 additions & 0 deletions test-grapesy/Test/Util/Awkward.hs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ instance Arbitrary (Awkward Text) where
arbitrary = Awkward . Text.pack . getAwkward <$> arbitrary
shrink = map (Awkward . Text.pack) . shrink . (Text.unpack . getAwkward)

instance Arbitrary (Awkward Int) where
arbitrary = Awkward <$> arbitrary
shrink = map Awkward . shrink . getAwkward

instance Arbitrary (Awkward Double) where
arbitrary = Awkward <$> arbitrary
shrink = map Awkward . shrink . getAwkward

0 comments on commit 5f3744c

Please sign in to comment.