Safe Haskell | None |
---|---|
Language | Haskell2010 |
Network.Craze
Description
Craze is a small module for performing multiple similar HTTP GET requests
in parallel. This is performed through the raceGet
function, which will
perform all the requests and pick the first successful response that passes
a certain check, meaning that the parallel requests are essentially racing
against each other.
What is the usefulness of this?
If you are dealing with data source or API that is very unreliable (high latency, random failures) and there are no limitations on performing significantly more requests, then performing multiple requests (through direct connections, proxies, VPNs) may increase the chances of getting a successful response faster and more reliably.
However, if using a different data source or transport is a possibility, it is potentially a better option that this approach.
Examples:
Performing two parallel GET requests against https://chromabits.com and returning the status code of the first successful one:
The providers generate two client configurations. The handler "parses" the response (in this case it just gets the status code). Finally, the checker filters out responses that we don't consider valid (anything that is not HTTP 200 in this case).
>>>
:set -XOverloadedStrings
>>>
:{
let racer = (Racer { racerProviders = [ simpleTagged [] "Client A" , simpleTagged [] "Client B" ] , racerHandler = return . respStatus , racerChecker = (200 ==) , racerDebug = False , racerReturnLast = False } :: Racer [(String, String)] ByteString Int) in (raceGet racer "https://chromabits.com" >>= print) :} Just 200
- type RacerHandler headerTy bodyTy a = CurlResponse_ headerTy bodyTy -> IO a
- type RacerChecker a = a -> Bool
- data Racer headerTy bodyTy a = Racer {
- racerHandler :: RacerHandler headerTy bodyTy a
- racerChecker :: RacerChecker a
- racerProviders :: [RacerProvider]
- racerDebug :: Bool
- racerReturnLast :: Bool
- type RacerProvider = IO ProviderOptions
- data ProviderOptions = ProviderOptions {}
- data RacerResult a = RacerResult {
- rrResponse :: Maybe a
- rrWinner :: Maybe ProviderOptions
- rrProviders :: [RacerProvider]
- rrStatuses :: [(Text, ClientStatus a)]
- data ClientStatus a
- = Successful a
- | Failed a
- | Errored SomeException
- | Pending
- raceGet :: (Eq a, CurlHeader ht, CurlBuffer bt, MonadIO m) => Racer ht bt a -> URLString -> m (Maybe a)
- raceGetResult :: (Eq a, CurlHeader ht, CurlBuffer bt, MonadIO m) => Racer ht bt a -> URLString -> m (RacerResult a)
- simple :: Monad m => [CurlOption] -> m ProviderOptions
- simpleTagged :: Monad m => [CurlOption] -> Text -> m ProviderOptions
- delayed :: Monad m => [CurlOption] -> Int -> m ProviderOptions
- delayedTagged :: Monad m => [CurlOption] -> Int -> Text -> m ProviderOptions
- defaultRacer :: Racer [(String, String)] ByteString ByteString
- defaultProviderOptions :: ProviderOptions
Types
type RacerHandler headerTy bodyTy a = CurlResponse_ headerTy bodyTy -> IO a Source
A RacerHandler
is simply a function for transforming a response after it
is received. The handler is only applied to successful requests before they
are checked by the RacerChecker
.
This is primarily for extracting or parsing a CurlResponse_
before doing
any further work. The type returned by the handler will be used as the
input of the checker and will be the return type of functions like
raceGet
.
type RacerChecker a = a -> Bool Source
A function that computes whether or not a result is valid or not.
A racer will discard successful responses it get from its clients if they do not pass the checker.
This step allows the racer to potentially discard responses that, while technically successful, do not contain the expected result (e.g. APIs that return errors as HTTP 200s, rate limitting messages, or unexpected formats).
data Racer headerTy bodyTy a Source
A record describing the rules for racing requests.
Constructors
Racer | |
Fields
|
Instances
Default (Racer [(String, String)] ByteString ByteString) Source |
type RacerProvider = IO ProviderOptions Source
A provider is simply a factory function for ProviderOptions
, which are
used to configure a client.
data ProviderOptions Source
Configuration used to set up an individual client in the race.
Constructors
ProviderOptions | |
Fields
|
Instances
data RacerResult a Source
The result of a racing operation. This can be used to collect statistics on which providers win more often, etc.
Constructors
RacerResult | |
Fields
|
data ClientStatus a Source
The status of running a single client.
Constructors
Successful a | A successful response (passed the checker). A race will usually only have one successful response. |
Failed a | A response that was received but failed to pass the checker. |
Errored SomeException | An exception thrown while using the client. |
Pending | The operation is still pending, was cancelled, or was never started. |
Instances
Show a => Show (ClientStatus a) Source |
Functions
raceGet :: (Eq a, CurlHeader ht, CurlBuffer bt, MonadIO m) => Racer ht bt a -> URLString -> m (Maybe a) Source
Perform a GET request on the provided URL using all providers in parallel.
Rough summary of the algorithm:
- Start all requests
Wait for a request to finish.
If the request is successful, apply the handler on it.
- If the result of the handler passes the checker, cancel all other requests, and return the result.
- If the check fails, go back to waiting for another request to finish.
- If the request fails, go back to waiting for another request to finish.
raceGetResult :: (Eq a, CurlHeader ht, CurlBuffer bt, MonadIO m) => Racer ht bt a -> URLString -> m (RacerResult a) Source
Same as raceGet
, but returns a RacerResult
which contains more
information about the race performed.
Providers
RacerProvider
provide client configurations. Craze comes bundled with a
few built-in providers which can be used for quickly building client
configurations.
simple :: Monad m => [CurlOption] -> m ProviderOptions Source
A simple provider. It does not delay requests.
simpleTagged :: Monad m => [CurlOption] -> Text -> m ProviderOptions Source
Like simple
, but with a tag for identification.
delayed :: Monad m => [CurlOption] -> Int -> m ProviderOptions Source
A provider which will delay a request by the provided number of microseconds.
delayedTagged :: Monad m => [CurlOption] -> Int -> Text -> m ProviderOptions Source
Like delayed
, but with a tag for identification.
Deprecated
defaultRacer :: Racer [(String, String)] ByteString ByteString Source
Deprecated: Use Data.Default.Class.def instead
A Racer
with some default values.
Note: The handler will extract the response body as a ByteString
and
ignore everything else, hence the type:
Racer [(String, String)] ByteString ByteString
If this is not the desired behavior, or if the response should be parsed or
processed, you should use the Racer
constructor directly and provide all
fields.
defaultProviderOptions :: ProviderOptions Source
Deprecated: Use Data.Default.Class.def instead
A default set of options for a provider.